Merge branch 'akpm' (patches from Andrew)

Merge second patch-bomb from Andrew Morton:

 - more MM stuff:

    - Kirill's page-flags rework

    - Kirill's now-allegedly-fixed THP rework

    - MADV_FREE implementation

    - DAX feature work (msync/fsync).  This isn't quite complete but DAX
      is new and it's good enough and the guys have a handle on what
      needs to be done - I expect this to be wrapped in the next week or
      two.

  - some vsprintf maintenance work

  - various other misc bits

* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (145 commits)
  printk: change recursion_bug type to bool
  lib/vsprintf: factor out %pN[F] handler as netdev_bits()
  lib/vsprintf: refactor duplicate code to special_hex_number()
  printk-formats.txt: remove unimplemented %pT
  printk: help pr_debug and pr_devel to optimize out arguments
  lib/test_printf.c: test dentry printing
  lib/test_printf.c: add test for large bitmaps
  lib/test_printf.c: account for kvasprintf tests
  lib/test_printf.c: add a few number() tests
  lib/test_printf.c: test precision quirks
  lib/test_printf.c: check for out-of-bound writes
  lib/test_printf.c: don't BUG
  lib/kasprintf.c: add sanity check to kvasprintf
  lib/vsprintf.c: warn about too large precisions and field widths
  lib/vsprintf.c: help gcc make number() smaller
  lib/vsprintf.c: expand field_width to 24 bits
  lib/vsprintf.c: eliminate potential race in string()
  lib/vsprintf.c: move string() below widen_string()
  lib/vsprintf.c: pull out padding code from dentry_name()
  printk: do cond_resched() between lines while outputting to consoles
  ...
diff --git a/Documentation/ABI/testing/sysfs-class-watchdog b/Documentation/ABI/testing/sysfs-class-watchdog
new file mode 100644
index 0000000..736046b
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-watchdog
@@ -0,0 +1,51 @@
+What:		/sys/class/watchdog/watchdogn/bootstatus
+Date:		August 2015
+Contact:	Wim Van Sebroeck <wim@iguana.be>
+Description:
+		It is a read only file. It contains status of the watchdog
+		device at boot. It is equivalent to WDIOC_GETBOOTSTATUS of
+		ioctl interface.
+
+What:		/sys/class/watchdog/watchdogn/identity
+Date:		August 2015
+Contact:	Wim Van Sebroeck <wim@iguana.be>
+Description:
+		It is a read only file. It contains identity string of
+		watchdog device.
+
+What:		/sys/class/watchdog/watchdogn/nowayout
+Date:		August 2015
+Contact:	Wim Van Sebroeck <wim@iguana.be>
+Description:
+		It is a read only file. While reading, it gives '1' if that
+		device supports nowayout feature else, it gives '0'.
+
+What:		/sys/class/watchdog/watchdogn/state
+Date:		August 2015
+Contact:	Wim Van Sebroeck <wim@iguana.be>
+Description:
+		It is a read only file. It gives active/inactive status of
+		watchdog device.
+
+What:		/sys/class/watchdog/watchdogn/status
+Date:		August 2015
+Contact:	Wim Van Sebroeck <wim@iguana.be>
+Description:
+		It is a read only file. It contains watchdog device's
+		internal status bits. It is equivalent to WDIOC_GETSTATUS
+		of ioctl interface.
+
+What:		/sys/class/watchdog/watchdogn/timeleft
+Date:		August 2015
+Contact:	Wim Van Sebroeck <wim@iguana.be>
+Description:
+		It is a read only file. It contains value of time left for
+		reset generation. It is equivalent to WDIOC_GETTIMELEFT of
+		ioctl interface.
+
+What:		/sys/class/watchdog/watchdogn/timeout
+Date:		August 2015
+Contact:	Wim Van Sebroeck <wim@iguana.be>
+Description:
+		It is a read only file. It is read to know about current
+		value of timeout programmed.
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
index c06f817..db65377 100644
--- a/Documentation/CodingStyle
+++ b/Documentation/CodingStyle
@@ -430,7 +430,7 @@
 		return result;
 	}
 
-A common type of bug to be aware of it "one err bugs" which look like this:
+A common type of bug to be aware of is "one err bugs" which look like this:
 
 	err:
 		kfree(foo->bar);
diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt
index 1e98a7e..45ef3f2 100644
--- a/Documentation/DMA-API.txt
+++ b/Documentation/DMA-API.txt
@@ -236,7 +236,7 @@
 
 DMA_TO_DEVICE synchronisation must be done after the last modification
 of the memory region by the software and before it is handed off to
-the driver.  Once this primitive is used, memory covered by this
+the device.  Once this primitive is used, memory covered by this
 primitive should be treated as read-only by the device.  If the device
 may write to it at any point, it should be DMA_BIDIRECTIONAL (see
 below).
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 91f6d89..d70f9b6 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -50,8 +50,7 @@
 
 HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS)))
 htmldocs: $(HTML)
-	$(call build_main_index)
-	$(call build_images)
+	$(call cmd,build_main_index)
 	$(call install_media_images)
 
 MAN := $(patsubst %.xml, %.9, $(BOOKS))
@@ -139,7 +138,8 @@
 
 index = index.html
 main_idx = $(obj)/$(index)
-build_main_index = rm -rf $(main_idx); \
+quiet_cmd_build_main_index = HTML    $(main_idx)
+      cmd_build_main_index = rm -rf $(main_idx); \
 		   echo '<h1>Linux Kernel HTML Documentation</h1>' >> $(main_idx) && \
 		   echo '<h2>Kernel Version: $(KERNELVERSION)</h2>' >> $(main_idx) && \
 		   cat $(HTML) >> $(main_idx)
@@ -227,6 +227,10 @@
 	@echo  '  mandocs         - man pages'
 	@echo  '  installmandocs  - install man pages generated by mandocs'
 	@echo  '  cleandocs       - clean all generated DocBook files'
+	@echo
+	@echo  'make DOCBOOKS="s1.xml s2.xml" [target] Generate only docs s1.xml s2.xml'
+	@echo  '  valid values for DOCBOOKS are: $(DOCBOOKS)'
+
 
 ###
 # Temporary files left by various tools
diff --git a/Documentation/DocBook/gpu.tmpl b/Documentation/DocBook/gpu.tmpl
index 201dcd3..03f01e7 100644
--- a/Documentation/DocBook/gpu.tmpl
+++ b/Documentation/DocBook/gpu.tmpl
@@ -615,18 +615,6 @@
           <function>drm_gem_object_init</function>. Storage for private GEM
           objects must be managed by drivers.
         </para>
-        <para>
-          Drivers that do not need to extend GEM objects with private information
-          can call the <function>drm_gem_object_alloc</function> function to
-          allocate and initialize a struct <structname>drm_gem_object</structname>
-          instance. The GEM core will call the optional driver
-          <methodname>gem_init_object</methodname> operation after initializing
-          the GEM object with <function>drm_gem_object_init</function>.
-          <synopsis>int (*gem_init_object) (struct drm_gem_object *obj);</synopsis>
-        </para>
-        <para>
-          No alloc-and-init function exists for private GEM objects.
-        </para>
       </sect3>
       <sect3>
         <title>GEM Objects Lifetime</title>
@@ -635,10 +623,10 @@
           acquired and release by <function>calling drm_gem_object_reference</function>
           and <function>drm_gem_object_unreference</function> respectively. The
           caller must hold the <structname>drm_device</structname>
-          <structfield>struct_mutex</structfield> lock. As a convenience, GEM
-          provides the <function>drm_gem_object_reference_unlocked</function> and
-          <function>drm_gem_object_unreference_unlocked</function> functions that
-          can be called without holding the lock.
+	  <structfield>struct_mutex</structfield> lock when calling
+	  <function>drm_gem_object_reference</function>. As a convenience, GEM
+	  provides <function>drm_gem_object_unreference_unlocked</function>
+	  functions that can be called without holding the lock.
         </para>
         <para>
           When the last reference to a GEM object is released the GEM core calls
@@ -649,15 +637,9 @@
         </para>
         <para>
           <synopsis>void (*gem_free_object) (struct drm_gem_object *obj);</synopsis>
-          Drivers are responsible for freeing all GEM object resources, including
-          the resources created by the GEM core. If an mmap offset has been
-          created for the object (in which case
-          <structname>drm_gem_object</structname>::<structfield>map_list</structfield>::<structfield>map</structfield>
-          is not NULL) it must be freed by a call to
-          <function>drm_gem_free_mmap_offset</function>. The shmfs backing store
-          must be released by calling <function>drm_gem_object_release</function>
-          (that function can safely be called if no shmfs backing store has been
-          created).
+          Drivers are responsible for freeing all GEM object resources. This includes
+          the resources created by the GEM core, which need to be released with
+          <function>drm_gem_object_release</function>.
         </para>
       </sect3>
       <sect3>
@@ -740,17 +722,10 @@
           DRM identifies the GEM object to be mapped by a fake offset passed
           through the mmap offset argument. Prior to being mapped, a GEM object
           must thus be associated with a fake offset. To do so, drivers must call
-          <function>drm_gem_create_mmap_offset</function> on the object. The
-          function allocates a fake offset range from a pool and stores the
-          offset divided by PAGE_SIZE in
-          <literal>obj-&gt;map_list.hash.key</literal>. Care must be taken not to
-          call <function>drm_gem_create_mmap_offset</function> if a fake offset
-          has already been allocated for the object. This can be tested by
-          <literal>obj-&gt;map_list.map</literal> being non-NULL.
+          <function>drm_gem_create_mmap_offset</function> on the object.
         </para>
         <para>
           Once allocated, the fake offset value
-          (<literal>obj-&gt;map_list.hash.key &lt;&lt; PAGE_SHIFT</literal>)
           must be passed to the application in a driver-specific way and can then
           be used as the mmap offset argument.
         </para>
@@ -836,10 +811,11 @@
           abstracted from the client in libdrm.
         </para>
       </sect3>
-      <sect3>
-        <title>GEM Function Reference</title>
+    </sect2>
+    <sect2>
+      <title>GEM Function Reference</title>
 !Edrivers/gpu/drm/drm_gem.c
-      </sect3>
+!Iinclude/drm/drm_gem.h
     </sect2>
     <sect2>
       <title>VMA Offset Manager</title>
@@ -4201,17 +4177,21 @@
       </sect2>
     </sect1>
     <sect1>
-      <title>GuC-based Command Submission</title>
+      <title>GuC</title>
       <sect2>
-        <title>GuC</title>
+        <title>GuC-specific firmware loader</title>
 !Pdrivers/gpu/drm/i915/intel_guc_loader.c GuC-specific firmware loader
 !Idrivers/gpu/drm/i915/intel_guc_loader.c
       </sect2>
       <sect2>
-        <title>GuC Client</title>
-!Pdrivers/gpu/drm/i915/i915_guc_submission.c GuC-based command submissison
+        <title>GuC-based command submission</title>
+!Pdrivers/gpu/drm/i915/i915_guc_submission.c GuC-based command submission
 !Idrivers/gpu/drm/i915/i915_guc_submission.c
       </sect2>
+      <sect2>
+        <title>GuC Firmware Layout</title>
+!Pdrivers/gpu/drm/i915/intel_guc_fwif.h GuC Firmware Layout
+      </sect2>
     </sect1>
 
     <sect1>
diff --git a/Documentation/DocBook/iio.tmpl b/Documentation/DocBook/iio.tmpl
index 98be322..f525bf5 100644
--- a/Documentation/DocBook/iio.tmpl
+++ b/Documentation/DocBook/iio.tmpl
@@ -458,7 +458,7 @@
             .scan_type = {
               .sign = 's',
               .realbits = 12,
-              .storgebits = 16,
+              .storagebits = 16,
               .shift = 4,
               .endianness = IIO_LE,
             },
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index 21152d3..d5a699d 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -209,7 +209,7 @@
 Cross-Reference project, which is able to present source code in a
 self-referential, indexed webpage format. An excellent up-to-date
 repository of the kernel code may be found at:
-	http://lxr.linux.no/+trees
+	http://lxr.free-electrons.com/
 
 
 The development process
diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c
index f405780..7785fb5 100644
--- a/Documentation/accounting/getdelays.c
+++ b/Documentation/accounting/getdelays.c
@@ -375,7 +375,8 @@
 		}
 	}
 
-	if ((nl_sd = create_nl_socket(NETLINK_GENERIC)) < 0)
+	nl_sd = create_nl_socket(NETLINK_GENERIC);
+	if (nl_sd < 0)
 		err(1, "error creating Netlink socket\n");
 
 
diff --git a/Documentation/arm/Marvell/README b/Documentation/arm/Marvell/README
index 18a775d..ae89b67 100644
--- a/Documentation/arm/Marvell/README
+++ b/Documentation/arm/Marvell/README
@@ -233,29 +233,30 @@
    Linux kernel mach directory: arch/arm/mach-mmp
    Linux kernel plat directory: arch/arm/plat-pxa
 
-Berlin family (Digital Entertainment)
+Berlin family (Multimedia Solutions)
 -------------------------------------
 
   Flavors:
-	88DE3005, Armada 1500-mini
+	88DE3005, Armada 1500 Mini
 		Design name:	BG2CD
 		Core:		ARM Cortex-A9, PL310 L2CC
-		Homepage:	http://www.marvell.com/digital-entertainment/armada-1500-mini/
+		Homepage:	http://www.marvell.com/multimedia-solutions/armada-1500-mini/
+        88DE3006, Armada 1500 Mini Plus
+                Design name:    BG2CDP
+                Core:           Dual Core ARM Cortex-A7
+                Homepage:       http://www.marvell.com/multimedia-solutions/armada-1500-mini-plus/
 	88DE3100, Armada 1500
 		Design name:	BG2
 		Core:		Marvell PJ4B (ARMv7), Tauros3 L2CC
-		Homepage:	http://www.marvell.com/digital-entertainment/armada-1500/
-		Product Brief:	http://www.marvell.com/digital-entertainment/armada-1500/assets/Marvell-ARMADA-1500-Product-Brief.pdf
+		Product Brief:	http://www.marvell.com/multimedia-solutions/armada-1500/assets/Marvell-ARMADA-1500-Product-Brief.pdf
 	88DE3114, Armada 1500 Pro
-		Design name:	BG2-Q
+		Design name:	BG2Q
 		Core:		Quad Core ARM Cortex-A9, PL310 L2CC
-		Homepage:	http://www.marvell.com/digital-entertainment/armada-1500-pro/
-		Product Brief:	http://www.marvell.com/digital-entertainment/armada-1500-pro/assets/Marvell_ARMADA_1500_PRO-01_product_brief.pdf
 	88DE????
 		Design name:	BG3
 		Core:		ARM Cortex-A15, CA15 integrated L2CC
 
-  Homepage: http://www.marvell.com/digital-entertainment/
+  Homepage: http://www.marvell.com/multimedia-solutions/
   Directory: arch/arm/mach-berlin
 
   Comments:
diff --git a/Documentation/block/cfq-iosched.txt b/Documentation/block/cfq-iosched.txt
index f3bc729..1e4f835 100644
--- a/Documentation/block/cfq-iosched.txt
+++ b/Documentation/block/cfq-iosched.txt
@@ -81,14 +81,13 @@
 
 Default value for this parameter is 8ms.
 
-latency
--------
-This parameter is used to enable/disable the latency mode of the CFQ
-scheduler. If latency mode (called low_latency) is enabled, CFQ tries
-to recompute the slice time for each process based on the target_latency set
-for the system. This favors fairness over throughput. Disabling low
-latency (setting it to 0) ignores target latency, allowing each process in the
-system to get a full time slice.
+low_latency
+-----------
+This parameter is used to enable/disable the low latency mode of the CFQ
+scheduler. If enabled, CFQ tries to recompute the slice time for each process
+based on the target_latency set for the system. This favors fairness over
+throughput. Disabling low latency (setting it to 0) ignores target latency,
+allowing each process in the system to get a full time slice.
 
 By default low latency mode is enabled.
 
diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
index f9ad5e0..dd68821 100644
--- a/Documentation/cpu-hotplug.txt
+++ b/Documentation/cpu-hotplug.txt
@@ -150,7 +150,7 @@
 
 If this is not mounted, do the following.
 
-	 #mkdir /sysfs
+	#mkdir /sys
 	#mount -t sysfs sys /sys
 
 Now you should see entries for all present cpu, the following is an example
diff --git a/Documentation/devicetree/bindings/clock/brcm,bcm2835-aux-clock.txt b/Documentation/devicetree/bindings/clock/brcm,bcm2835-aux-clock.txt
new file mode 100644
index 0000000..7a837d2
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/brcm,bcm2835-aux-clock.txt
@@ -0,0 +1,31 @@
+Broadcom BCM2835 auxiliary peripheral support
+
+This binding uses the common clock binding:
+    Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The auxiliary peripherals (UART, SPI1, and SPI2) have a small register
+area controlling clock gating to the peripherals, and providing an IRQ
+status register.
+
+Required properties:
+- compatible:	Should be "brcm,bcm2835-aux"
+- #clock-cells:	Should be <1>. The permitted clock-specifier values can be
+		  found in include/dt-bindings/clock/bcm2835-aux.h
+- reg:		Specifies base physical address and size of the registers
+- clocks:	The parent clock phandle
+
+Example:
+
+	clocks: cprman@7e101000 {
+		compatible = "brcm,bcm2835-cprman";
+		#clock-cells = <1>;
+		reg = <0x7e101000 0x2000>;
+		clocks = <&clk_osc>;
+	};
+
+	aux: aux@0x7e215004 {
+		compatible = "brcm,bcm2835-aux";
+		#clock-cells = <1>;
+		reg = <0x7e215000 0x8>;
+		clocks = <&clocks BCM2835_CLOCK_VPU>;
+	};
diff --git a/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt b/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt
index ede65a5..0b35e71 100644
--- a/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt
+++ b/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt
@@ -208,3 +208,8 @@
     ch3_unused	lcpll_ports	4	BCM_NS2_LCPLL_PORTS_CH3_UNUSED
     ch4_unused	lcpll_ports	5	BCM_NS2_LCPLL_PORTS_CH4_UNUSED
     ch5_unused	lcpll_ports	6	BCM_NS2_LCPLL_PORTS_CH5_UNUSED
+
+BCM63138
+--------
+PLL and leaf clock compatible strings for BCM63138 are:
+    "brcm,bcm63138-armpll"
diff --git a/Documentation/devicetree/bindings/clock/cs2000-cp.txt b/Documentation/devicetree/bindings/clock/cs2000-cp.txt
new file mode 100644
index 0000000..54e6df0
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/cs2000-cp.txt
@@ -0,0 +1,22 @@
+CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier
+
+Required properties:
+
+- compatible:		"cirrus,cs2000-cp"
+- reg:			The chip select number on the I2C bus
+- clocks:		common clock binding for CLK_IN, XTI/REF_CLK
+- clock-names:		CLK_IN : clk_in, XTI/REF_CLK : ref_clk
+- #clock-cells:		must be <0>
+
+Example:
+
+&i2c2 {
+	...
+	cs2000: clk_multiplier@4f {
+		#clock-cells = <0>;
+		compatible = "cirrus,cs2000-cp";
+		reg = <0x4f>;
+		clocks = <&rcar_sound 0>, <&x12_clk>;
+		clock-names = "clk_in", "ref_clk";
+	};
+};
diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra210-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra210-car.txt
new file mode 100644
index 0000000..26f237f
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/nvidia,tegra210-car.txt
@@ -0,0 +1,56 @@
+NVIDIA Tegra210 Clock And Reset Controller
+
+This binding uses the common clock binding:
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The CAR (Clock And Reset) Controller on Tegra is the HW module responsible
+for muxing and gating Tegra's clocks, and setting their rates.
+
+Required properties :
+- compatible : Should be "nvidia,tegra210-car"
+- reg : Should contain CAR registers location and length
+- clocks : Should contain phandle and clock specifiers for two clocks:
+  the 32 KHz "32k_in".
+- #clock-cells : Should be 1.
+  In clock consumers, this cell represents the clock ID exposed by the
+  CAR. The assignments may be found in header file
+  <dt-bindings/clock/tegra210-car.h>.
+- #reset-cells : Should be 1.
+  In clock consumers, this cell represents the bit number in the CAR's
+  array of CLK_RST_CONTROLLER_RST_DEVICES_* registers.
+
+Example SoC include file:
+
+/ {
+	tegra_car: clock {
+		compatible = "nvidia,tegra210-car";
+		reg = <0x60006000 0x1000>;
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+	usb@c5004000 {
+		clocks = <&tegra_car TEGRA210_CLK_USB2>;
+	};
+};
+
+Example board file:
+
+/ {
+	clocks {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		clk_32k: clock@1 {
+			compatible = "fixed-clock";
+			reg = <1>;
+			#clock-cells = <0>;
+			clock-frequency = <32768>;
+		};
+	};
+
+	&tegra_car {
+		clocks = <&clk_32k>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/clock/nxp,lpc3220-clk.txt b/Documentation/devicetree/bindings/clock/nxp,lpc3220-clk.txt
new file mode 100644
index 0000000..20cbca3
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/nxp,lpc3220-clk.txt
@@ -0,0 +1,30 @@
+NXP LPC32xx Clock Controller
+
+Required properties:
+- compatible: should be "nxp,lpc3220-clk"
+- reg:  should contain clock controller registers location and length
+- #clock-cells: must be 1, the cell holds id of a clock provided by the
+  clock controller
+- clocks: phandles of external oscillators, the list must contain one
+  32768 Hz oscillator and may have one optional high frequency oscillator
+- clock-names: list of external oscillator clock names, must contain
+  "xtal_32k" and may have optional "xtal"
+
+Examples:
+
+	/* System Control Block */
+	scb {
+		compatible = "simple-bus";
+		ranges = <0x0 0x040004000 0x00001000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		clk: clock-controller@0 {
+			compatible = "nxp,lpc3220-clk";
+			reg = <0x00 0x114>;
+			#clock-cells = <1>;
+
+			clocks = <&xtal_32k>, <&xtal>;
+			clock-names = "xtal_32k", "xtal";
+		};
+	};
diff --git a/Documentation/devicetree/bindings/clock/nxp,lpc3220-usb-clk.txt b/Documentation/devicetree/bindings/clock/nxp,lpc3220-usb-clk.txt
new file mode 100644
index 0000000..0aa2494
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/nxp,lpc3220-usb-clk.txt
@@ -0,0 +1,22 @@
+NXP LPC32xx USB Clock Controller
+
+Required properties:
+- compatible: should be "nxp,lpc3220-usb-clk"
+- reg:  should contain clock controller registers location and length
+- #clock-cells: must be 1, the cell holds id of a clock provided by the
+  USB clock controller
+
+Examples:
+
+	usb {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		ranges = <0x0 0x31020000 0x00001000>;
+
+		usbclk: clock-controller@f00 {
+			compatible = "nxp,lpc3220-usb-clk";
+			reg = <0xf00 0x100>;
+			#clock-cells = <1>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index 152dfaa..72f82f4 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -13,6 +13,7 @@
 			"qcom,gcc-msm8974"
 			"qcom,gcc-msm8974pro"
 			"qcom,gcc-msm8974pro-ac"
+			"qcom,gcc-msm8996"
 
 - reg : shall contain base register location and length
 - #clock-cells : shall contain 1
diff --git a/Documentation/devicetree/bindings/clock/qcom,mmcc.txt b/Documentation/devicetree/bindings/clock/qcom,mmcc.txt
index 34e7614..8b0f784 100644
--- a/Documentation/devicetree/bindings/clock/qcom,mmcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,mmcc.txt
@@ -9,6 +9,7 @@
 			"qcom,mmcc-msm8660"
 			"qcom,mmcc-msm8960"
 			"qcom,mmcc-msm8974"
+			"qcom,mmcc-msm8996"
 
 - reg : shall contain base register location and length
 - #clock-cells : shall contain 1
diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
index 38dcf03..ae36ab8 100644
--- a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
+++ b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
@@ -20,6 +20,10 @@
     clocks must be specified.  For clocks with multiple parents, invalid
     settings must be specified as "<0>".
   - #clock-cells: Must be 0
+
+
+Optional Properties:
+
   - clock-output-names: The name of the clock as a free-form string
 
 
diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3036-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3036-cru.txt
new file mode 100644
index 0000000..ace0599
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/rockchip,rk3036-cru.txt
@@ -0,0 +1,56 @@
+* Rockchip RK3036 Clock and Reset Unit
+
+The RK3036 clock controller generates and supplies clock to various
+controllers within the SoC and also implements a reset controller for SoC
+peripherals.
+
+Required Properties:
+
+- compatible: should be "rockchip,rk3036-cru"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- #clock-cells: should be 1.
+- #reset-cells: should be 1.
+
+Optional Properties:
+
+- rockchip,grf: phandle to the syscon managing the "general register files"
+  If missing pll rates are not changeable, due to the missing pll lock status.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. All available clocks are defined as
+preprocessor macros in the dt-bindings/clock/rk3036-cru.h headers and can be
+used in device tree sources. Similar macros exist for the reset sources in
+these files.
+
+External clocks:
+
+There are several clocks that are generated outside the SoC. It is expected
+that they are defined using standard clock bindings with following
+clock-output-names:
+ - "xin24m" - crystal input - required,
+ - "ext_i2s" - external I2S clock - optional,
+ - "ext_gmac" - external GMAC clock - optional
+
+Example: Clock controller node:
+
+	cru: cru@20000000 {
+		compatible = "rockchip,rk3036-cru";
+		reg = <0x20000000 0x1000>;
+		rockchip,grf = <&grf>;
+
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+Example: UART controller node that consumes the clock generated by the clock
+  controller:
+
+	uart0: serial@20060000 {
+		compatible = "snps,dw-apb-uart";
+		reg = <0x20060000 0x100>;
+		interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&cru SCLK_UART0>;
+	};
diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3228-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3228-cru.txt
new file mode 100644
index 0000000..f323048
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/rockchip,rk3228-cru.txt
@@ -0,0 +1,58 @@
+* Rockchip RK3228 Clock and Reset Unit
+
+The RK3228 clock controller generates and supplies clock to various
+controllers within the SoC and also implements a reset controller for SoC
+peripherals.
+
+Required Properties:
+
+- compatible: should be "rockchip,rk3228-cru"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- #clock-cells: should be 1.
+- #reset-cells: should be 1.
+
+Optional Properties:
+
+- rockchip,grf: phandle to the syscon managing the "general register files"
+  If missing pll rates are not changeable, due to the missing pll lock status.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. All available clocks are defined as
+preprocessor macros in the dt-bindings/clock/rk3228-cru.h headers and can be
+used in device tree sources. Similar macros exist for the reset sources in
+these files.
+
+External clocks:
+
+There are several clocks that are generated outside the SoC. It is expected
+that they are defined using standard clock bindings with following
+clock-output-names:
+ - "xin24m" - crystal input - required,
+ - "ext_i2s" - external I2S clock - optional,
+ - "ext_gmac" - external GMAC clock - optional
+ - "ext_hsadc" - external HSADC clock - optional
+ - "phy_50m_out" - output clock of the pll in the mac phy
+
+Example: Clock controller node:
+
+	cru: cru@20000000 {
+		compatible = "rockchip,rk3228-cru";
+		reg = <0x20000000 0x1000>;
+		rockchip,grf = <&grf>;
+
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+Example: UART controller node that consumes the clock generated by the clock
+  controller:
+
+	uart0: serial@10110000 {
+		compatible = "snps,dw-apb-uart";
+		reg = <0x10110000 0x100>;
+		interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&cru SCLK_UART0>;
+	};
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index 8a47b77..e59f57b 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -27,7 +27,9 @@
 	"allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
 	"allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20
 	"allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31
+	"allwinner,sun9i-a80-cpus-clk" - for the CPUS on A80
 	"allwinner,sun6i-a31-ahb1-clk" - for the AHB1 clock on A31
+	"allwinner,sun8i-h3-ahb2-clk" - for the AHB2 clock on H3
 	"allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
 	"allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
 	"allwinner,sun9i-a80-ahb0-gates-clk" - for the AHB0 gates on A80
@@ -55,6 +57,9 @@
 	"allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80
 	"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
 	"allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
+	"allwinner,sun8i-h3-bus-gates-clk" - for the bus gates on H3
+	"allwinner,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80
+	"allwinner,sun4i-a10-dram-gates-clk" - for the DRAM gates on A10
 	"allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
 	"allwinner,sun4i-a10-mmc-clk" - for the MMC clock
 	"allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
@@ -68,8 +73,10 @@
 	"allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
 	"allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
 	"allwinner,sun8i-a23-usb-clk" - for usb gates + resets on A23
+	"allwinner,sun8i-h3-usb-clk" - for usb gates + resets on H3
 	"allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80
 	"allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80
+	"allwinner,sun4i-a10-ve-clk" - for the Video Engine clock
 
 Required properties for all clocks:
 - reg : shall be the control register address for the clock.
@@ -89,6 +96,9 @@
 And "allwinner,*-usb-clk" clocks also require:
 - reset-cells : shall be set to 1
 
+The "allwinner,sun4i-a10-ve-clk" clock also requires:
+- reset-cells : shall be set to 0
+
 The "allwinner,sun9i-a80-mmc-config-clk" clock also requires:
 - #reset-cells : shall be set to 1
 - resets : shall be the reset control phandle for the mmc block.
diff --git a/Documentation/devicetree/bindings/clock/tango4-clock.txt b/Documentation/devicetree/bindings/clock/tango4-clock.txt
new file mode 100644
index 0000000..19c580a
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/tango4-clock.txt
@@ -0,0 +1,23 @@
+* Sigma Designs Tango4 Clock Generator
+
+The Tango4 clock generator outputs cpu_clk and sys_clk (the latter is used
+for RAM and various peripheral devices). The clock binding described here
+is applicable to all Tango4 SoCs.
+
+Required Properties:
+
+- compatible: should be "sigma,tango4-clkgen".
+- reg: physical base address of the device and length of memory mapped region.
+- clocks: phandle of the input clock (crystal oscillator).
+- clock-output-names: should be "cpuclk" and "sysclk".
+- #clock-cells: should be set to 1.
+
+Example:
+
+	clkgen: clkgen@10000 {
+		compatible = "sigma,tango4-clkgen";
+		reg = <0x10000 0x40>;
+		clocks = <&xtal>;
+		clock-output-names = "cpuclk", "sysclk";
+		#clock-cells = <1>;
+	};
diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
index 13df993..6b4a98f 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
@@ -25,6 +25,7 @@
 	ti,tca6416
 	ti,tca6424
 	ti,tca9539
+	onsemi,pca9654
 	exar,xra1202
 
 Example:
diff --git a/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt b/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt
index ba2bb84..c809acb 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt
@@ -5,7 +5,8 @@
 
 - compatible: should be "semtech,sx1506q",
 			"semtech,sx1508q",
-			"semtech,sx1509q".
+			"semtech,sx1509q",
+			"semtech,sx1502q".
 
 - reg: The I2C slave address for this device.
 
diff --git a/Documentation/devicetree/bindings/gpio/gpio-tps65086.txt b/Documentation/devicetree/bindings/gpio/gpio-tps65086.txt
new file mode 100644
index 0000000..ba05107
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-tps65086.txt
@@ -0,0 +1,16 @@
+* TPS65086 GPO Controller bindings
+
+Required properties:
+ - compatible		: Should be "ti,tps65086-gpio".
+ - gpio-controller	: Marks the device node as a GPIO Controller.
+ - #gpio-cells		: Should be two. The first cell is the pin number
+			    and the second cell is used to specify flags.
+			    See ../gpio/gpio.txt for possible values.
+
+Example:
+
+	gpio4: gpio {
+		compatible = "ti,tps65086-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
diff --git a/Documentation/devicetree/bindings/sound/ak4613.txt b/Documentation/devicetree/bindings/sound/ak4613.txt
index 15a9195..1783f9e 100644
--- a/Documentation/devicetree/bindings/sound/ak4613.txt
+++ b/Documentation/devicetree/bindings/sound/ak4613.txt
@@ -7,6 +7,16 @@
 - compatible : "asahi-kasei,ak4613"
 - reg : The chip select number on the I2C bus
 
+Optional properties:
+- asahi-kasei,in1-single-end	: Boolean. Indicate input / output pins are single-ended.
+- asahi-kasei,in2-single-end	  rather than differential.
+- asahi-kasei,out1-single-end
+- asahi-kasei,out2-single-end
+- asahi-kasei,out3-single-end
+- asahi-kasei,out4-single-end
+- asahi-kasei,out5-single-end
+- asahi-kasei,out6-single-end
+
 Example:
 
 &i2c {
diff --git a/Documentation/devicetree/bindings/sound/atmel-pdmic.txt b/Documentation/devicetree/bindings/sound/atmel-pdmic.txt
new file mode 100644
index 0000000..e0875f1
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/atmel-pdmic.txt
@@ -0,0 +1,55 @@
+* Atmel PDMIC driver under ALSA SoC architecture
+
+Required properties:
+- compatible
+	Should be "atmel,sama5d2-pdmic".
+- reg
+	Should contain PDMIC registers location and length.
+- interrupts
+	Should contain the IRQ line for the PDMIC.
+- dmas
+	One DMA specifiers as described in atmel-dma.txt and dma.txt files.
+- dma-names
+	Must be "rx".
+- clock-names
+	Required elements:
+	- "pclk"	peripheral clock
+	- "gclk"	generated clock
+- clocks
+	Must contain an entry for each required entry in clock-names.
+	Please refer to clock-bindings.txt.
+- atmel,mic-min-freq
+	The minimal frequency that the micphone supports.
+- atmel,mic-max-freq
+	The maximal frequency that the micphone supports.
+
+Optional properties:
+- pinctrl-names, pinctrl-0
+	Please refer to pinctrl-bindings.txt.
+- atmel,model
+	The user-visible name of this sound card.
+	The default value is "PDMIC".
+- atmel,mic-offset
+	The offset that should be added.
+	The range is from -32768 to 32767.
+	The default value is 0.
+
+Example:
+	pdmic@f8018000 {
+				compatible = "atmel,sama5d2-pdmic";
+				reg = <0xf8018000 0x124>;
+				interrupts = <48 IRQ_TYPE_LEVEL_HIGH 7>;
+				dmas = <&dma0
+					(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+					| AT91_XDMAC_DT_PERID(50))>;
+				dma-names = "rx";
+				clocks = <&pdmic_clk>, <&pdmic_gclk>;
+				clock-names = "pclk", "gclk";
+
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_pdmic_default>;
+				atmel,model = "PDMIC @ sama5d2_xplained";
+				atmel,mic-min-freq = <1000000>;
+				atmel,mic-max-freq = <3246000>;
+				atmel,mic-offset = <0x0>;
+	};
diff --git a/Documentation/devicetree/bindings/sound/da7218.txt b/Documentation/devicetree/bindings/sound/da7218.txt
new file mode 100644
index 0000000..5ca5a70
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/da7218.txt
@@ -0,0 +1,104 @@
+Dialog Semiconductor DA7218 Audio Codec bindings
+
+DA7218 is an audio codec with HP detect feature.
+
+======
+
+Required properties:
+- compatible : Should be "dlg,da7217" or "dlg,da7218"
+- reg: Specifies the I2C slave address
+
+- VDD-supply: VDD power supply for the device
+- VDDMIC-supply: VDDMIC power supply for the device
+- VDDIO-supply: VDDIO power supply for the device
+  (See Documentation/devicetree/bindings/regulator/regulator.txt for further
+   information relating to regulators)
+
+Optional properties:
+- interrupt-parent: Specifies the phandle of the interrupt controller to which
+  the IRQs from DA7218 are delivered to.
+- interrupts: IRQ line info for DA7218 chip.
+  (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for
+   further information relating to interrupt properties)
+- interrupt-names : Name associated with interrupt line. Should be "wakeup" if
+  interrupt is to be used to wake system, otherwise "irq" should be used.
+- wakeup-source: Flag to indicate this device can wake system (suspend/resume).
+
+- clocks : phandle and clock specifier for codec MCLK.
+- clock-names : Clock name string for 'clocks' attribute, should be "mclk".
+
+- dlg,micbias1-lvl-millivolt : Voltage (mV) for Mic Bias 1
+	[<1200>, <1600>, <1800>, <2000>, <2200>, <2400>, <2600>, <2800>, <3000>]
+- dlg,micbias2-lvl-millivolt : Voltage (mV) for Mic Bias 2
+	[<1200>, <1600>, <1800>, <2000>, <2200>, <2400>, <2600>, <2800>, <3000>]
+- dlg,mic1-amp-in-sel : Mic1 input source type
+	["diff", "se_p", "se_n"]
+- dlg,mic2-amp-in-sel : Mic2 input source type
+	["diff", "se_p", "se_n"]
+- dlg,dmic1-data-sel : DMIC1 channel select based on clock edge.
+	["lrise_rfall", "lfall_rrise"]
+- dlg,dmic1-samplephase : When to sample audio from DMIC1.
+	["on_clkedge", "between_clkedge"]
+- dlg,dmic1-clkrate-hz : DMic1 clock frequency (Hz).
+	[<1500000>, <3000000>]
+- dlg,dmic2-data-sel : DMic2 channel select based on clock edge.
+	["lrise_rfall", "lfall_rrise"]
+- dlg,dmic2-samplephase : When to sample audio from DMic2.
+	["on_clkedge", "between_clkedge"]
+- dlg,dmic2-clkrate-hz : DMic2 clock frequency (Hz).
+	[<1500000>, <3000000>]
+- dlg,hp-diff-single-supply : Boolean flag, use single supply for HP
+			      (DA7217 only)
+
+======
+
+Optional Child node - 'da7218_hpldet' (DA7218 only):
+
+Optional properties:
+- dlg,jack-rate-us : Time between jack detect measurements (us)
+	[<5>, <10>, <20>, <40>, <80>, <160>, <320>, <640>]
+- dlg,jack-debounce : Number of debounce measurements taken for jack detect
+	[<0>, <2>, <3>, <4>]
+- dlg,jack-threshold-pct : Threshold level for jack detection (% of VDD)
+	[<84>, <88>, <92>, <96>]
+- dlg,comp-inv : Boolean flag, invert comparator output
+- dlg,hyst : Boolean flag, enable hysteresis
+- dlg,discharge : Boolean flag, auto discharge of Mic Bias on jack removal
+
+======
+
+Example:
+
+	codec: da7218@1a {
+		compatible = "dlg,da7218";
+		reg = <0x1a>;
+		interrupt-parent = <&gpio6>;
+		interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
+		wakeup-source;
+
+		VDD-supply = <&reg_audio>;
+		VDDMIC-supply = <&reg_audio>;
+		VDDIO-supply = <&reg_audio>;
+
+		clocks = <&clks 201>;
+		clock-names = "mclk";
+
+		dlg,micbias1-lvl-millivolt = <2600>;
+		dlg,micbias2-lvl-millivolt = <2600>;
+		dlg,mic1-amp-in-sel = "diff";
+		dlg,mic2-amp-in-sel = "diff";
+
+		dlg,dmic1-data-sel = "lrise_rfall";
+		dlg,dmic1-samplephase = "on_clkedge";
+		dlg,dmic1-clkrate-hz = <3000000>;
+		dlg,dmic2-data-sel = "lrise_rfall";
+		dlg,dmic2-samplephase = "on_clkedge";
+		dlg,dmic2-clkrate-hz = <3000000>;
+
+		da7218_hpldet {
+			dlg,jack-rate-us = <40>;
+			dlg,jack-debounce = <2>;
+			dlg,jack-threshold-pct = <84>;
+			dlg,hyst;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/sound/da7219.txt b/Documentation/devicetree/bindings/sound/da7219.txt
index 1b70309..cf61681 100644
--- a/Documentation/devicetree/bindings/sound/da7219.txt
+++ b/Documentation/devicetree/bindings/sound/da7219.txt
@@ -28,13 +28,15 @@
 - clocks : phandle and clock specifier for codec MCLK.
 - clock-names : Clock name string for 'clocks' attribute, should be "mclk".
 
-- dlg,ldo-lvl : Required internal LDO voltage (mV) level for digital engine
-	[<1050>, <1100>, <1200>, <1400>]
 - dlg,micbias-lvl : Voltage (mV) for Mic Bias
-	[<1800>, <2000>, <2200>, <2400>, <2600>]
+	[<1600>, <1800>, <2000>, <2200>, <2400>, <2600>]
 - dlg,mic-amp-in-sel : Mic input source type
 	["diff", "se_p", "se_n"]
 
+Deprecated properties:
+- dlg,ldo-lvl : Required internal LDO voltage (mV) level for digital engine
+  (LDO unavailable in production HW so property no longer required).
+
 ======
 
 Child node - 'da7219_aad':
diff --git a/Documentation/devicetree/bindings/sound/fsl,asrc.txt b/Documentation/devicetree/bindings/sound/fsl,asrc.txt
index b93362a..3e26a94 100644
--- a/Documentation/devicetree/bindings/sound/fsl,asrc.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,asrc.txt
@@ -25,6 +25,11 @@
 	"mem"		  Peripheral access clock to access registers.
 	"ipg"		  Peripheral clock to driver module.
 	"asrck_<0-f>"	  Clock sources for input and output clock.
+	"spba"		  The spba clock is required when ASRC is placed as a
+			  bus slave of the Shared Peripheral Bus and when two
+			  or more bus masters (CPU, DMA or DSP) try to access
+			  it. This property is optional depending on the SoC
+			  design.
 
    - big-endian		: If this property is absent, the little endian mode
 			  will be in use as default. Otherwise, the big endian
diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt
index d3b6b5f..cd3ee5d 100644
--- a/Documentation/devicetree/bindings/sound/fsl,esai.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt
@@ -27,6 +27,11 @@
 			  derive HCK, SCK and FS.
 	"fsys"		  The system clock derived from ahb clock used to
 			  derive HCK, SCK and FS.
+	"spba"		  The spba clock is required when ESAI is placed as a
+			  bus slave of the Shared Peripheral Bus and when two
+			  or more bus masters (CPU, DMA or DSP) try to access
+			  it. This property is optional depending on the SoC
+			  design.
 
   - fsl,fifo-depth	: The number of elements in the transmit and receive
 			  FIFOs. This number is the maximum allowed value for
diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
index b5ee32e..4ca39dd 100644
--- a/Documentation/devicetree/bindings/sound/fsl,spdif.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
@@ -27,6 +27,11 @@
 			  Transceiver Clock Diagram" of SoC reference manual.
 			  It can also be referred to TxClk_Source bit of
 			  register SPDIF_STC.
+	"spba"		  The spba clock is required when SPDIF is placed as a
+			  bus slave of the Shared Peripheral Bus and when two
+			  or more bus masters (CPU, DMA or DSP) try to access
+			  it. This property is optional depending on the SoC
+			  design.
 
    - big-endian		: If this property is absent, the native endian mode
 			  will be in use as default, or the big endian mode
diff --git a/Documentation/devicetree/bindings/sound/img,i2s-in.txt b/Documentation/devicetree/bindings/sound/img,i2s-in.txt
new file mode 100644
index 0000000..423265c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/img,i2s-in.txt
@@ -0,0 +1,47 @@
+Imagination Technologies I2S Input Controller
+
+Required Properties:
+
+  - compatible : Compatible list, must contain "img,i2s-in"
+
+  - #sound-dai-cells : Must be equal to 0
+
+  - reg : Offset and length of the register set for the device
+
+  - clocks : Contains an entry for each entry in clock-names
+
+  - clock-names : Must include the following entry:
+	"sys"	The system clock
+
+  - dmas: Contains an entry for each entry in dma-names.
+
+  - dma-names: Must include the following entry:
+	"rx"	Single DMA channel used by all active I2S channels
+
+  - img,i2s-channels : Number of I2S channels instantiated in the I2S in block
+
+Optional Properties:
+
+  - interrupts : Contains the I2S in interrupts. Depending on
+	the configuration, there may be no interrupts, one interrupt,
+	or an interrupt per I2S channel. For the case where there is
+	one interrupt per channel, the interrupts should be listed
+	in ascending channel order
+
+  - resets: Contains a phandle to the I2S in reset signal
+
+  - reset-names: Contains the reset signal name "rst"
+
+Example:
+
+i2s_in: i2s-in@18100800 {
+	compatible = "img,i2s-in";
+	reg = <0x18100800 0x200>;
+	interrupts = <GIC_SHARED 7 IRQ_TYPE_LEVEL_HIGH>;
+	dmas = <&mdc 30 0xffffffff 0>;
+	dma-names = "rx";
+	clocks = <&cr_periph SYS_CLK_I2S_IN>;
+	clock-names = "sys";
+	img,i2s-channels = <6>;
+	#sound-dai-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/img,i2s-out.txt b/Documentation/devicetree/bindings/sound/img,i2s-out.txt
new file mode 100644
index 0000000..0159415
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/img,i2s-out.txt
@@ -0,0 +1,51 @@
+Imagination Technologies I2S Output Controller
+
+Required Properties:
+
+  - compatible : Compatible list, must contain "img,i2s-out"
+
+  - #sound-dai-cells : Must be equal to 0
+
+  - reg : Offset and length of the register set for the device
+
+  - clocks : Contains an entry for each entry in clock-names
+
+  - clock-names : Must include the following entries:
+	"sys"	The system clock
+	"ref"	The reference clock
+
+  - dmas: Contains an entry for each entry in dma-names.
+
+  - dma-names: Must include the following entry:
+	"tx"	Single DMA channel used by all active I2S channels
+
+  - img,i2s-channels : Number of I2S channels instantiated in the I2S out block
+
+  - resets: Contains a phandle to the I2S out reset signal
+
+  - reset-names: Contains the reset signal name "rst"
+
+Optional Properties:
+
+  - interrupts : Contains the I2S out interrupts. Depending on
+	the configuration, there may be no interrupts, one interrupt,
+	or an interrupt per I2S channel. For the case where there is
+	one interrupt per channel, the interrupts should be listed
+	in ascending channel order
+
+Example:
+
+i2s_out: i2s-out@18100A00 {
+	compatible = "img,i2s-out";
+	reg = <0x18100A00 0x200>;
+	interrupts = <GIC_SHARED 13 IRQ_TYPE_LEVEL_HIGH>;
+	dmas = <&mdc 23 0xffffffff 0>;
+	dma-names = "tx";
+	clocks = <&cr_periph SYS_CLK_I2S_OUT>,
+		 <&clk_core CLK_I2S>;
+	clock-names = "sys", "ref";
+	img,i2s-channels = <6>;
+	resets = <&pistachio_reset PISTACHIO_RESET_I2S_OUT>;
+	reset-names = "rst";
+	#sound-dai-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/img,parallel-out.txt b/Documentation/devicetree/bindings/sound/img,parallel-out.txt
new file mode 100644
index 0000000..a3015d2
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/img,parallel-out.txt
@@ -0,0 +1,44 @@
+Imagination Technologies Parallel Output Controller
+
+Required Properties:
+
+  - compatible : Compatible list, must contain "img,parallel-out".
+
+  - #sound-dai-cells : Must be equal to 0
+
+  - reg : Offset and length of the register set for the device.
+
+  - dmas: Contains an entry for each entry in dma-names.
+
+  - dma-names: Must include the following entry:
+	"tx"
+
+  - clocks : Contains an entry for each entry in clock-names.
+
+  - clock-names : Includes the following entries:
+	"sys"	The system clock
+	"ref"	The reference clock
+
+  - resets: Contains a phandle to the parallel out reset signal
+
+  - reset-names: Contains the reset signal name "rst"
+
+Optional Properties:
+
+  - interrupts : Contains the parallel out interrupt, if present
+
+Example:
+
+parallel_out: parallel-out@18100C00 {
+	compatible = "img,parallel-out";
+	reg = <0x18100C00 0x100>;
+	interrupts = <GIC_SHARED 19 IRQ_TYPE_LEVEL_HIGH>;
+	dmas = <&mdc 16 0xffffffff 0>;
+	dma-names = "tx";
+	clocks = <&cr_periph SYS_CLK_PAUD_OUT>,
+		 <&clk_core CLK_AUDIO_DAC>;
+	clock-names = "sys", "ref";
+	resets = <&pistachio_reset PISTACHIO_RESET_PRL_OUT>;
+	reset-names = "rst";
+	#sound-dai-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/img,pistachio-internal-dac.txt b/Documentation/devicetree/bindings/sound/img,pistachio-internal-dac.txt
new file mode 100644
index 0000000..4cc18fc
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/img,pistachio-internal-dac.txt
@@ -0,0 +1,18 @@
+Pistachio internal DAC DT bindings
+
+Required properties:
+
+  - compatible: "img,pistachio-internal-dac"
+
+  - img,cr-top : Must contain a phandle to the top level control syscon
+		 node which contains the internal dac control registers
+
+  - VDD-supply : Digital power supply regulator (+1.8V or +3.3V)
+
+Examples:
+
+internal_dac: internal-dac {
+	compatible = "img,pistachio-internal-dac";
+	img,cr-top = <&cr_top>;
+	VDD-supply = <&supply3v3>;
+};
diff --git a/Documentation/devicetree/bindings/sound/img,spdif-in.txt b/Documentation/devicetree/bindings/sound/img,spdif-in.txt
new file mode 100644
index 0000000..aab9a81
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/img,spdif-in.txt
@@ -0,0 +1,41 @@
+Imagination Technologies SPDIF Input Controller
+
+Required Properties:
+
+  - compatible : Compatible list, must contain "img,spdif-in"
+
+  - #sound-dai-cells : Must be equal to 0
+
+  - reg : Offset and length of the register set for the device
+
+  - dmas: Contains an entry for each entry in dma-names.
+
+  - dma-names: Must include the following entry:
+	"rx"
+
+  - clocks : Contains an entry for each entry in clock-names
+
+  - clock-names : Includes the following entries:
+	"sys"	The system clock
+
+Optional Properties:
+
+  - resets: Should contain a phandle to the spdif in reset signal, if any
+
+  - reset-names: Should contain the reset signal name "rst", if a
+	reset phandle is given
+
+  - interrupts : Contains the spdif in interrupt, if present
+
+Example:
+
+spdif_in: spdif-in@18100E00 {
+	compatible = "img,spdif-in";
+	reg = <0x18100E00 0x100>;
+	interrupts = <GIC_SHARED 20 IRQ_TYPE_LEVEL_HIGH>;
+	dmas = <&mdc 15 0xffffffff 0>;
+	dma-names = "rx";
+	clocks = <&cr_periph SYS_CLK_SPDIF_IN>;
+	clock-names = "sys";
+	#sound-dai-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/img,spdif-out.txt b/Documentation/devicetree/bindings/sound/img,spdif-out.txt
new file mode 100644
index 0000000..470a519
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/img,spdif-out.txt
@@ -0,0 +1,44 @@
+Imagination Technologies SPDIF Output Controller
+
+Required Properties:
+
+  - compatible : Compatible list, must contain "img,spdif-out"
+
+  - #sound-dai-cells : Must be equal to 0
+
+  - reg : Offset and length of the register set for the device
+
+  - dmas: Contains an entry for each entry in dma-names.
+
+  - dma-names: Must include the following entry:
+	"tx"
+
+  - clocks : Contains an entry for each entry in clock-names.
+
+  - clock-names : Includes the following entries:
+	"sys"	The system clock
+	"ref"	The reference clock
+
+  - resets: Contains a phandle to the spdif out reset signal
+
+  - reset-names: Contains the reset signal name "rst"
+
+Optional Properties:
+
+  - interrupts : Contains the parallel out interrupt, if present
+
+Example:
+
+spdif_out: spdif-out@18100D00 {
+	compatible = "img,spdif-out";
+	reg = <0x18100D00 0x100>;
+	interrupts = <GIC_SHARED 21 IRQ_TYPE_LEVEL_HIGH>;
+	dmas = <&mdc 14 0xffffffff 0>;
+	dma-names = "tx";
+	clocks = <&cr_periph SYS_CLK_SPDIF_OUT>,
+		 <&clk_core CLK_SPDIF>;
+	clock-names = "sys", "ref";
+	resets = <&pistachio_reset PISTACHIO_RESET_SPDIF_OUT>;
+	reset-names = "rst";
+	#sound-dai-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/inno-rk3036.txt b/Documentation/devicetree/bindings/sound/inno-rk3036.txt
new file mode 100644
index 0000000..758de8e
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/inno-rk3036.txt
@@ -0,0 +1,20 @@
+Inno audio codec for RK3036
+
+Inno audio codec is integrated inside RK3036 SoC.
+
+Required properties:
+- compatible : Should be "rockchip,rk3036-codec".
+- reg : The registers of codec.
+- clock-names : Should be "acodec_pclk".
+- clocks : The clock of codec.
+- rockchip,grf : The phandle of grf device node.
+
+Example:
+
+	acodec: acodec-ana@20030000 {
+		compatible = "rk3036-codec";
+		reg = <0x20030000 0x4000>;
+		rockchip,grf = <&grf>;
+		clock-names = "acodec_pclk";
+		clocks = <&cru ACLK_VCODEC>;
+	};
diff --git a/Documentation/devicetree/bindings/sound/pcm1792a.txt b/Documentation/devicetree/bindings/sound/pcm179x.txt
similarity index 87%
rename from Documentation/devicetree/bindings/sound/pcm1792a.txt
rename to Documentation/devicetree/bindings/sound/pcm179x.txt
index 970ba1e..4ae70d3 100644
--- a/Documentation/devicetree/bindings/sound/pcm1792a.txt
+++ b/Documentation/devicetree/bindings/sound/pcm179x.txt
@@ -1,4 +1,4 @@
-Texas Instruments pcm1792a DT bindings
+Texas Instruments pcm179x DT bindings
 
 This driver supports the SPI bus.
 
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
index c57cbd6..8ee0fa9 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
@@ -7,8 +7,11 @@
 				  "renesas,rcar_sound-gen3" if generation3
 				  Examples with soctypes are:
 				    - "renesas,rcar_sound-r8a7778" (R-Car M1A)
+				    - "renesas,rcar_sound-r8a7779" (R-Car H1)
 				    - "renesas,rcar_sound-r8a7790" (R-Car H2)
 				    - "renesas,rcar_sound-r8a7791" (R-Car M2-W)
+				    - "renesas,rcar_sound-r8a7793" (R-Car M2-N)
+				    - "renesas,rcar_sound-r8a7794" (R-Car E2)
 				    - "renesas,rcar_sound-r8a7795" (R-Car H3)
 - reg				: Should contain the register physical address.
 				  required register is
@@ -34,6 +37,8 @@
 				  see below for detail.
 - #sound-dai-cells		: it must be 0 if your system is using single DAI
 				  it must be 1 if your system is using multi  DAI
+
+Optional properties:
 - #clock-cells			: it must be 0 if your system has audio_clkout
 				  it must be 1 if your system has audio_clkout0/1/2/3
 - clock-frequency		: for all audio_clkout0/1/2/3
@@ -244,3 +249,80 @@
 		};
 	};
 };
+
+Example: simple sound card
+
+	rsnd_ak4643: sound {
+		compatible = "simple-audio-card";
+
+		simple-audio-card,format = "left_j";
+		simple-audio-card,bitclock-master = <&sndcodec>;
+		simple-audio-card,frame-master = <&sndcodec>;
+
+		sndcpu: simple-audio-card,cpu {
+			sound-dai = <&rcar_sound>;
+		};
+
+		sndcodec: simple-audio-card,codec {
+			sound-dai = <&ak4643>;
+			clocks = <&audio_clock>;
+		};
+	};
+
+&rcar_sound {
+	pinctrl-0 = <&sound_pins &sound_clk_pins>;
+	pinctrl-names = "default";
+
+	/* Single DAI */
+	#sound-dai-cells = <0>;
+
+	status = "okay";
+
+	rcar_sound,dai {
+		dai0 {
+			playback = <&ssi0 &src2 &dvc0>;
+			capture  = <&ssi1 &src3 &dvc1>;
+		};
+	};
+};
+
+&ssi1 {
+	shared-pin;
+};
+
+Example: simple sound card for TDM
+
+	rsnd_tdm: sound {
+		compatible = "simple-audio-card";
+
+		simple-audio-card,format = "left_j";
+		simple-audio-card,bitclock-master = <&sndcodec>;
+		simple-audio-card,frame-master = <&sndcodec>;
+
+		sndcpu: simple-audio-card,cpu {
+			sound-dai = <&rcar_sound>;
+			dai-tdm-slot-num = <6>;
+		};
+
+		sndcodec: simple-audio-card,codec {
+			sound-dai = <&xxx>;
+		};
+	};
+
+Example: simple sound card for Multi channel
+
+&rcar_sound {
+	pinctrl-0 = <&sound_pins &sound_clk_pins>;
+	pinctrl-names = "default";
+
+	/* Single DAI */
+	#sound-dai-cells = <0>;
+
+	status = "okay";
+
+	rcar_sound,dai {
+		dai0 {
+			playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>;
+		};
+	};
+};
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
index 962748a..2b2caa2 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
+++ b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
@@ -4,8 +4,8 @@
 
 Required properties:
 
-- compatible				: "renesas,rsrc-card,<board>"
-					  Examples with soctypes are:
+- compatible				: "renesas,rsrc-card{,<board>}"
+					  Examples with boards are:
 					    - "renesas,rsrc-card"
 					    - "renesas,rsrc-card,lager"
 					    - "renesas,rsrc-card,koelsch"
diff --git a/Documentation/devicetree/bindings/sound/rockchip-i2s.txt b/Documentation/devicetree/bindings/sound/rockchip-i2s.txt
index 2267d24..b7f3a93 100644
--- a/Documentation/devicetree/bindings/sound/rockchip-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/rockchip-i2s.txt
@@ -19,6 +19,7 @@
 - clock-names: should contain followings:
    - "i2s_hclk": clock for I2S BUS
    - "i2s_clk" : clock for I2S controller
+- rockchip,playback-channels: max playback channels, if not set, 8 channels default.
 - rockchip,capture-channels: max capture channels, if not set, 2 channels default.
 
 Example for rk3288 I2S controller:
@@ -31,5 +32,6 @@
 	dma-names = "tx", "rx";
 	clock-names = "i2s_hclk", "i2s_clk";
 	clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
+	rockchip,playback-channels = <8>;
 	rockchip,capture-channels = <2>;
 };
diff --git a/Documentation/devicetree/bindings/sound/rt5616.txt b/Documentation/devicetree/bindings/sound/rt5616.txt
new file mode 100644
index 0000000..efc48c6
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rt5616.txt
@@ -0,0 +1,26 @@
+RT5616 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt5616".
+
+- reg : The I2C address of the device.
+
+Pins on the device (for linking into audio routes) for RT5616:
+
+  * IN1P
+  * IN2P
+  * IN2N
+  * LOUTL
+  * LOUTR
+  * HPOL
+  * HPOR
+
+Example:
+
+codec: rt5616@1b {
+	compatible = "realtek,rt5616";
+	reg = <0x1b>;
+};
diff --git a/Documentation/devicetree/bindings/sound/rt5651.txt b/Documentation/devicetree/bindings/sound/rt5651.txt
new file mode 100644
index 0000000..38752330
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rt5651.txt
@@ -0,0 +1,41 @@
+RT5651 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt5651".
+
+- reg : The I2C address of the device.
+
+Optional properties:
+
+- realtek,in2-differential
+  Boolean. Indicate MIC2 input are differential, rather than single-ended.
+
+- realtek,dmic-en
+  Boolean. true if dmic is used.
+
+Pins on the device (for linking into audio routes) for RT5651:
+
+  * DMIC L1
+  * DMIC R1
+  * IN1P
+  * IN2P
+  * IN2N
+  * IN3P
+  * HPOL
+  * HPOR
+  * LOUTL
+  * LOUTR
+  * PDML
+  * PDMR
+
+Example:
+
+codec: rt5651@1a {
+	compatible = "realtek,rt5651";
+	reg = <0x1a>;
+	realtek,dmic-en = "true";
+	realtek,in2-diff = "false";
+};
diff --git a/Documentation/devicetree/bindings/sound/rt5659.txt b/Documentation/devicetree/bindings/sound/rt5659.txt
new file mode 100644
index 0000000..5f79e7f
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rt5659.txt
@@ -0,0 +1,75 @@
+RT5659/RT5658 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : One of "realtek,rt5659" or "realtek,rt5658".
+
+- reg : The I2C address of the device.
+
+- interrupts : The CODEC's interrupt output.
+
+Optional properties:
+
+- realtek,in1-differential
+- realtek,in3-differential
+- realtek,in4-differential
+  Boolean. Indicate MIC1/3/4 input are differential, rather than single-ended.
+
+- realtek,dmic1-data-pin
+  0: dmic1 is not used
+  1: using IN2N pin as dmic1 data pin
+  2: using GPIO5 pin as dmic1 data pin
+  3: using GPIO9 pin as dmic1 data pin
+  4: using GPIO11 pin as dmic1 data pin
+
+- realtek,dmic2-data-pin
+  0: dmic2 is not used
+  1: using IN2P pin as dmic2 data pin
+  2: using GPIO6 pin as dmic2 data pin
+  3: using GPIO10 pin as dmic2 data pin
+  4: using GPIO12 pin as dmic2 data pin
+
+- realtek,jd-src
+  0: No JD is used
+  1: using JD3 as JD source
+
+- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
+- realtek,reset-gpios : The GPIO that controls the CODEC's RESET pin.
+
+Pins on the device (for linking into audio routes) for RT5659/RT5658:
+
+  * DMIC L1
+  * DMIC R1
+  * DMIC L2
+  * DMIC R2
+  * IN1P
+  * IN1N
+  * IN2P
+  * IN2N
+  * IN3P
+  * IN3N
+  * IN4P
+  * IN4N
+  * HPOL
+  * HPOR
+  * SPOL
+  * SPOR
+  * LOUTL
+  * LOUTR
+  * MONOOUT
+  * PDML
+  * PDMR
+  * SPDIF
+
+Example:
+
+rt5659 {
+	compatible = "realtek,rt5659";
+	reg = <0x1b>;
+	interrupt-parent = <&gpio>;
+	interrupts = <TEGRA_GPIO(W, 3) GPIO_ACTIVE_HIGH>;
+	realtek,ldo1-en-gpios =
+		<&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
+};
diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt
index f070789..1b3c13d 100644
--- a/Documentation/devicetree/bindings/sound/rt5677.txt
+++ b/Documentation/devicetree/bindings/sound/rt5677.txt
@@ -18,7 +18,7 @@
 Optional properties:
 
 - realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin.
-- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin.
+- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin. Active low.
 
 - realtek,in1-differential
 - realtek,in2-differential
diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
index c92966b..0dce690 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
@@ -14,6 +14,9 @@
    - "apb": the parent APB clock for this controller
    - "codec": the parent module clock
 
+Optional properties:
+- allwinner,pa-gpios: gpio to enable external amplifier
+
 Example:
 codec: codec@01c22c00 {
 	#sound-dai-cells = <0>;
diff --git a/Documentation/devicetree/bindings/sound/ti,pcm3168a.txt b/Documentation/devicetree/bindings/sound/ti,pcm3168a.txt
new file mode 100644
index 0000000..5d9cb84
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ti,pcm3168a.txt
@@ -0,0 +1,48 @@
+Texas Instruments pcm3168a DT bindings
+
+This driver supports both SPI and I2C bus access for this codec
+
+Required properties:
+
+  - compatible: "ti,pcm3168a"
+
+  - clocks : Contains an entry for each entry in clock-names
+
+  - clock-names : Includes the following entries:
+	"scki"	The system clock
+
+  - VDD1-supply : Digital power supply regulator 1 (+3.3V)
+
+  - VDD2-supply : Digital power supply regulator 2 (+3.3V)
+
+  - VCCAD1-supply : ADC power supply regulator 1 (+5V)
+
+  - VCCAD2-supply : ADC power supply regulator 2 (+5V)
+
+  - VCCDA1-supply : DAC power supply regulator 1 (+5V)
+
+  - VCCDA2-supply : DAC power supply regulator 2 (+5V)
+
+For required properties on SPI/I2C, consult SPI/I2C device tree documentation
+
+Examples:
+
+i2c0: i2c0@0 {
+
+	...
+
+	pcm3168a: audio-codec@44 {
+		compatible = "ti,pcm3168a";
+		reg = <0x44>;
+		clocks = <&clk_core CLK_AUDIO>;
+		clock-names = "scki";
+		VDD1-supply = <&supply3v3>;
+		VDD2-supply = <&supply3v3>;
+		VCCAD1-supply = <&supply5v0>;
+		VCCAD2-supply = <&supply5v0>;
+		VCCDA1-supply = <&supply5v0>;
+		VCCDA2-supply = <&supply5v0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&dac_clk_pin>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8974.txt b/Documentation/devicetree/bindings/sound/wlf,wm8974.txt
new file mode 100644
index 0000000..01d3a7c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8974.txt
@@ -0,0 +1,15 @@
+WM8974 audio CODEC
+
+This device supports both I2C and SPI (configured with pin strapping
+on the board).
+
+Required properties:
+  - compatible: "wlf,wm8974"
+  - reg: the I2C address or SPI chip select number of the device
+
+Examples:
+
+codec: wm8974@1a {
+	compatible = "wlf,wm8974";
+	reg = <0x1a>;
+};
diff --git a/Documentation/devicetree/bindings/watchdog/alphascale-asm9260.txt b/Documentation/devicetree/bindings/watchdog/alphascale-asm9260.txt
new file mode 100644
index 0000000..75b265a
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/alphascale-asm9260.txt
@@ -0,0 +1,35 @@
+Alphascale asm9260 Watchdog timer
+
+Required properties:
+
+- compatible : should be "alphascale,asm9260-wdt".
+- reg : Specifies base physical address and size of the registers.
+- clocks : the clocks feeding the watchdog timer. See clock-bindings.txt
+- clock-names : should be set to
+	"mod" - source for tick counter.
+	"ahb" - ahb gate.
+- resets : phandle pointing to the system reset controller with
+	line index for the watchdog.
+- reset-names : should be set to "wdt_rst".
+
+Optional properties:
+- timeout-sec : shall contain the default watchdog timeout in seconds,
+	if unset, the default timeout is 30 seconds.
+- alphascale,mode : three modes are supported
+	"hw" - hw reset (default).
+	"sw" - sw reset.
+	"debug" - no action is taken.
+
+Example:
+
+watchdog0: watchdog@80048000 {
+	compatible = "alphascale,asm9260-wdt";
+	reg = <0x80048000 0x10>;
+	clocks = <&acc CLKID_SYS_WDT>, <&acc CLKID_AHB_WDT>;
+	clock-names = "mod", "ahb";
+	interrupts = <55>;
+	resets = <&rst WDT_RESET>;
+	reset-names = "wdt_rst";
+	timeout-sec = <30>;
+	alphascale,mode = "hw";
+};
diff --git a/Documentation/devicetree/bindings/watchdog/mt7621-wdt.txt b/Documentation/devicetree/bindings/watchdog/mt7621-wdt.txt
new file mode 100644
index 0000000..c15ef0e
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/mt7621-wdt.txt
@@ -0,0 +1,12 @@
+Ralink Watchdog Timers
+
+Required properties:
+- compatible: must be "mediatek,mt7621-wdt"
+- reg: physical base address of the controller and length of the register range
+
+Example:
+
+	watchdog@100 {
+		compatible = "mediatek,mt7621-wdt";
+		reg = <0x100 0x10>;
+	};
diff --git a/Documentation/devicetree/bindings/watchdog/sigma,smp8642-wdt.txt b/Documentation/devicetree/bindings/watchdog/sigma,smp8642-wdt.txt
new file mode 100644
index 0000000..5b7ec2c
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/sigma,smp8642-wdt.txt
@@ -0,0 +1,18 @@
+Sigma Designs SMP86xx/SMP87xx watchdog
+
+Required properties:
+- compatible: Should be "sigma,smp8642-wdt"
+- reg: Specifies the physical address region
+- clocks: Should be a phandle to the clock
+
+Optional properties:
+- timeout-sec: watchdog timeout in seconds
+
+Example:
+
+watchdog@1fd00 {
+	compatible = "sigma,smp8642-wdt";
+	reg = <0x1fd00 8>;
+	clocks = <&xtal_in_clk>;
+	timeout-sec = <30>;
+};
diff --git a/Documentation/devicetree/bindings/watchdog/ts4800-wdt.txt b/Documentation/devicetree/bindings/watchdog/ts4800-wdt.txt
new file mode 100644
index 0000000..8f6caad
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/ts4800-wdt.txt
@@ -0,0 +1,25 @@
+Technologic Systems Watchdog
+
+Required properties:
+- compatible: must be "technologic,ts4800-wdt"
+- syscon: phandle / integer array that points to the syscon node which
+          describes the FPGA's syscon registers.
+          - phandle to FPGA's syscon
+          - offset to the watchdog register
+
+Optional property:
+- timeout-sec: contains the watchdog timeout in seconds.
+
+Example:
+
+syscon: syscon@b0010000 {
+	compatible = "syscon", "simple-mfd";
+	reg = <0xb0010000 0x3d>;
+	reg-io-width = <2>;
+
+	wdt@e {
+		compatible = "technologic,ts4800-wdt";
+		syscon = <&syscon 0xe>;
+		timeout-sec = <10>;
+	};
+}
diff --git a/Documentation/devicetree/bindings/watchdog/ziirave-wdt.txt b/Documentation/devicetree/bindings/watchdog/ziirave-wdt.txt
new file mode 100644
index 0000000..3d87818
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/ziirave-wdt.txt
@@ -0,0 +1,19 @@
+Zodiac RAVE Watchdog Timer
+
+Required properties:
+- compatible: must be "zii,rave-wdt"
+- reg: i2c slave address of device, usually 0x38
+
+Optional Properties:
+- timeout-sec: Watchdog timeout value in seconds.
+- reset-duration-ms: Duration of the pulse generated when the watchdog times
+  out. Value in milliseconds.
+
+Example:
+
+	watchdog@38 {
+		compatible = "zii,rave-wdt";
+		reg = <0x38>;
+		timeout-sec = <30>;
+		reset-duration-ms = <30>;
+	};
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index e95aa1c..fde9fd0 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -820,7 +820,7 @@
 type exist.
 
 If min_free_kbytes has been tuned correctly (recommendations made by hugeadm
-from libhugetlbfs http://sourceforge.net/projects/libhugetlbfs/), one can
+from libhugetlbfs https://github.com/libhugetlbfs/libhugetlbfs/), one can
 make an estimate of the likely number of huge pages that can be allocated
 at a given point in time. All the "Movable" blocks should be allocatable
 unless memory has been mlock()'d. Some of the Reclaimable blocks should
diff --git a/Documentation/filesystems/sharedsubtree.txt b/Documentation/filesystems/sharedsubtree.txt
index 32a173d..e3f4c77 100644
--- a/Documentation/filesystems/sharedsubtree.txt
+++ b/Documentation/filesystems/sharedsubtree.txt
@@ -664,7 +664,7 @@
 		if one rbind mounts a tree within the same subtree 'n' times
 		the number of mounts created is an exponential function of 'n'.
 		Having unbindable mount can help prune the unneeded bind
-		mounts. Here is a example.
+		mounts. Here is an example.
 
 		step 1:
 		   let's say the root tree has just two directories with
diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt
index e000502..05676fd 100644
--- a/Documentation/gpio/consumer.txt
+++ b/Documentation/gpio/consumer.txt
@@ -260,7 +260,7 @@
 
 To summarize:
 
-Function (example)               active-low proporty  physical line
+Function (example)               active-low property  physical line
 gpiod_set_raw_value(desc, 0);        don't care           low
 gpiod_set_raw_value(desc, 1);        don't care           high
 gpiod_set_value(desc, 0);       default (active-high)     low
diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt
index 12a6194..bbeec41 100644
--- a/Documentation/gpio/driver.txt
+++ b/Documentation/gpio/driver.txt
@@ -113,8 +113,8 @@
   it will be threaded IRQ handler on -RT and hard IRQ handler on non-RT
   (for example, see [3]).
   Know W/A: The generic_handle_irq() is expected to be called with IRQ disabled,
-  so IRQ core will complain if it will be called from IRQ handler wich is forced
-  thread. The "fake?" raw lock can be used to W/A this problem:
+  so IRQ core will complain if it will be called from IRQ handler which is
+  forced thread. The "fake?" raw lock can be used to W/A this problem:
 
 	raw_spinlock_t wa_lock;
 	static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
@@ -224,7 +224,7 @@
 ---------------------------------------
 
 Any provider of irqchips needs to be carefully tailored to support Real Time
-preemption. It is desireable that all irqchips in the GPIO subsystem keep this
+preemption. It is desirable that all irqchips in the GPIO subsystem keep this
 in mind and does the proper testing to assure they are real time-enabled.
 So, pay attention on above " RT_FULL:" notes, please.
 The following is a checklist to follow when preparing a driver for real
diff --git a/Documentation/gpio/drivers-on-gpio.txt b/Documentation/gpio/drivers-on-gpio.txt
index f612132..14bf95a 100644
--- a/Documentation/gpio/drivers-on-gpio.txt
+++ b/Documentation/gpio/drivers-on-gpio.txt
@@ -54,7 +54,7 @@
   drivers for the I2C devices on the bus like any other I2C bus driver.
 
 - spi_gpio: drivers/spi/spi-gpio.c is used to drive an SPI bus (variable number
-  of wires, atleast SCK and optionally MISO, MOSI and chip select lines) using
+  of wires, at least SCK and optionally MISO, MOSI and chip select lines) using
   GPIO hammering (bitbang). It will appear as any other SPI bus on the system
   and makes it possible to connect drivers for SPI devices on the bus like
   any other SPI bus driver. For example any MMC/SD card can then be connected
@@ -75,7 +75,7 @@
 
 - gpio-wdt: drivers/watchdog/gpio_wdt.c is used to provide a watchdog timer
   that will periodically "ping" a hardware connected to a GPIO line by toggling
-  it from 1-to-0-to-1. If that hardware does not recieve its "ping"
+  it from 1-to-0-to-1. If that hardware does not receive its "ping"
   periodically, it will reset the system.
 
 - gpio-nand: drivers/mtd/nand/gpio.c is used to connect a NAND flash chip to
@@ -91,5 +91,5 @@
 
 Use those instead of talking directly to the GPIOs using sysfs; they integrate
 with kernel frameworks better than your userspace code could. Needless to say,
-just using the apropriate kernel drivers will simplify and speed up your
+just using the appropriate kernel drivers will simplify and speed up your
 embedded hacking in particular by providing ready-made components.
diff --git a/Documentation/ioctl/botching-up-ioctls.txt b/Documentation/ioctl/botching-up-ioctls.txt
index 45fe78c..cc30b14 100644
--- a/Documentation/ioctl/botching-up-ioctls.txt
+++ b/Documentation/ioctl/botching-up-ioctls.txt
@@ -122,7 +122,7 @@
 ----------------------------
 
 GPUs do most everything asynchronously, so we have a need to time operations and
-wait for oustanding ones. This is really tricky business; at the moment none of
+wait for outstanding ones. This is really tricky business; at the moment none of
 the ioctls supported by the drm/i915 get this fully right, which means there's
 still tons more lessons to learn here.
 
@@ -146,7 +146,7 @@
    ioctl restartable relative timeouts tend to be too coarse and can
    indefinitely extend your wait time due to rounding on each restart.
    Especially if your reference clock is something really slow like the display
-   frame counter. With a spec laywer hat on this isn't a bug since timeouts can
+   frame counter. With a spec lawyer hat on this isn't a bug since timeouts can
    always be extended - but users will surely hate you if their neat animations
    starts to stutter due to this.
 
@@ -176,7 +176,7 @@
 
  * Ensure that you have sufficient insulation between different clients. By
    default pick a private per-fd namespace which forces any sharing to be done
-   explictly. Only go with a more global per-device namespace if the objects
+   explicitly. Only go with a more global per-device namespace if the objects
    are truly device-unique. One counterexample in the drm modeset interfaces is
    that the per-device modeset objects like connectors share a namespace with
    framebuffer objects, which mostly are not shared at all. A separate
diff --git a/Documentation/ja_JP/HOWTO b/Documentation/ja_JP/HOWTO
index 5a0f2bd..8d5465d 100644
--- a/Documentation/ja_JP/HOWTO
+++ b/Documentation/ja_JP/HOWTO
@@ -245,7 +245,7 @@
 自己参照方式で、索引がついた web 形式で、ソースコードを参照することが
 できます。この最新の素晴しいカーネルコードのリポジトリは以下で見つかり
 ます-
-	http://lxr.linux.no/+trees
+	http://lxr.free-electrons.com/
 
 開発プロセス
 -----------------------
@@ -366,7 +366,6 @@
 に全サブシステムツリーからほぼ毎日プルされてできる特別なテスト用のリ
 ポジトリが存在します-
        http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
-       http://linux.f-seidel.de/linux-next/pmwiki/
 
 このやり方によって、-next カーネルは次のマージ機会でどんなものがメイン
 ラインカーネルにマージされるか、おおまかなの展望を提供します。-next 
diff --git a/Documentation/kernel-docs.txt b/Documentation/kernel-docs.txt
index 0891336..fe217c1 100644
--- a/Documentation/kernel-docs.txt
+++ b/Documentation/kernel-docs.txt
@@ -631,7 +631,7 @@
        between two versions of a file".
 
      * Name: "Cross-Referencing Linux"
-       URL: http://lxr.linux.no/source/
+       URL: http://lxr.free-electrons.com/
        Keywords: Browsing source code.
        Description: Another web-based Linux kernel source code browser.
        Lots of cross references to variables and functions. You can see
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 5a6235e..3ea869d 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -2748,10 +2748,16 @@
 				hardware access methods are allowed. Use this
 				if you experience crashes upon bootup and you
 				suspect they are caused by the BIOS.
-		conf1		[X86] Force use of PCI Configuration
-				Mechanism 1.
-		conf2		[X86] Force use of PCI Configuration
-				Mechanism 2.
+		conf1		[X86] Force use of PCI Configuration Access
+				Mechanism 1 (config address in IO port 0xCF8,
+				data in IO port 0xCFC, both 32-bit).
+		conf2		[X86] Force use of PCI Configuration Access
+				Mechanism 2 (IO port 0xCF8 is an 8-bit port for
+				the function, IO port 0xCFA, also 8-bit, sets
+				bus number. The config space is then accessed
+				through ports 0xC000-0xCFFF).
+				See http://wiki.osdev.org/PCI for more info
+				on the configuration access mechanisms.
 		noaer		[PCIE] If the PCIEAER kernel config parameter is
 				enabled, this kernel boot option can be used to
 				disable the use of PCIE advanced error reporting.
@@ -3071,9 +3077,6 @@
 	raid=		[HW,RAID]
 			See Documentation/md.txt.
 
-	ramdisk_blocksize=	[RAM]
-			See Documentation/blockdev/ramdisk.txt.
-
 	ramdisk_size=	[RAM] Sizes of RAM disks in kilobytes
 			See Documentation/blockdev/ramdisk.txt.
 
diff --git a/Documentation/ko_KR/HOWTO b/Documentation/ko_KR/HOWTO
index dc2ff8f..1aef53e 100644
--- a/Documentation/ko_KR/HOWTO
+++ b/Documentation/ko_KR/HOWTO
@@ -213,7 +213,7 @@
 것은 Linux Cross-Reference project이며 그것은 자기 참조 방식이며
 소스코드를 인덱스된 웹 페이지들의 형태로 보여준다. 최신의 멋진 커널
 코드 저장소는 다음을 통하여 참조할 수 있다.
-      http://lxr.linux.no/+trees
+      http://lxr.free-electrons.com/
 
 
 개발 프로세스
@@ -222,16 +222,16 @@
 리눅스 커널 개발 프로세스는 현재 몇몇 다른 메인 커널 "브랜치들"과
 서브시스템에 특화된 커널 브랜치들로 구성된다. 몇몇 다른 메인
 브랜치들은 다음과 같다.
-  - main 3.x 커널 트리
-  - 3.x.y - 안정된 커널 트리
-  - 3.x -git 커널 패치들
+  - main 4.x 커널 트리
+  - 4.x.y - 안정된 커널 트리
+  - 4.x -git 커널 패치들
   - 서브시스템을 위한 커널 트리들과 패치들
-  - 3.x - 통합 테스트를 위한 next 커널 트리
+  - 4.x - 통합 테스트를 위한 next 커널 트리
 
-3.x 커널 트리
+4.x 커널 트리
 ---------------
 
-3.x 커널들은 Linux Torvalds가 관리하며 kernel.org의 pub/linux/kernel/v3.x/
+4.x 커널들은 Linux Torvalds가 관리하며 kernel.org의 pub/linux/kernel/v4.x/
 디렉토리에서 참조될 수 있다.개발 프로세스는 다음과 같다.
   - 새로운 커널이 배포되자마자 2주의 시간이 주어진다. 이 기간동은
     메인테이너들은 큰 diff들을 Linus에게 제출할 수 있다. 대개 이 패치들은
@@ -262,20 +262,20 @@
          버그의 상황에 따라 배포되는 것이지 미리정해 놓은 시간에 따라
          배포되는 것은 아니기 때문이다."
 
-3.x.y - 안정 커널 트리
+4.x.y - 안정 커널 트리
 ------------------------
 
-3 자리 숫자로 이루어진 버젼의 커널들은 -stable 커널들이다. 그것들은 3.x
+3 자리 숫자로 이루어진 버젼의 커널들은 -stable 커널들이다. 그것들은 4.x
 커널에서 발견된 큰 회귀들이나 보안 문제들 중 비교적 작고 중요한 수정들을
 포함한다.
 
 이것은 가장 최근의 안정적인 커널을 원하는 사용자에게 추천되는 브랜치이며,
 개발/실험적 버젼을 테스트하는 것을 돕고자 하는 사용자들과는 별로 관련이 없다.
 
-어떤 3.x.y 커널도 사용할 수 없다면 그때는 가장 높은 숫자의 3.x
+어떤 4.x.y 커널도 사용할 수 없다면 그때는 가장 높은 숫자의 4.x
 커널이 현재의 안정 커널이다.
 
-3.x.y는 "stable" 팀<stable@vger.kernel.org>에 의해 관리되며 거의 매번 격주로
+4.x.y는 "stable" 팀<stable@vger.kernel.org>에 의해 관리되며 거의 매번 격주로
 배포된다.
 
 커널 트리 문서들 내에 Documentation/stable_kernel_rules.txt 파일은 어떤
@@ -283,7 +283,7 @@
 진행되는지를 설명한다.
 
 
-3.x -git 패치들
+4.x -git 패치들
 ------------------
 git 저장소(그러므로 -git이라는 이름이 붙음)에는 날마다 관리되는 Linus의
 커널 트리의 snapshot 들이 있다. 이 패치들은 일반적으로 날마다 배포되며
@@ -312,13 +312,12 @@
 대부분의 이러한 patchwork 사이트는 http://patchwork.kernel.org/ 또는
 http://patchwork.ozlabs.org/ 에 나열되어 있다.
 
-3.x - 통합 테스트를 위한 next 커널 트리
+4.x - 통합 테스트를 위한 next 커널 트리
 -----------------------------------------
-서브시스템 트리들의 변경사항들은 mainline 3.x 트리로 들어오기 전에 통합
+서브시스템 트리들의 변경사항들은 mainline 4.x 트리로 들어오기 전에 통합
 테스트를 거쳐야 한다. 이런 목적으로, 모든 서브시스템 트리의 변경사항을 거의
 매일 받아가는 특수한 테스트 저장소가 존재한다:
        http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git
-       http://linux.f-seidel.de/linux-next/pmwiki/
 
 이런 식으로, -next 커널을 통해 다음 머지 기간에 메인라인 커널에 어떤 변경이
 가해질 것인지 간략히 알 수 있다. 모험심 강한 테스터라면 -next 커널에서 테스트를
diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt
index 05fd83b..6ab619f 100644
--- a/Documentation/networking/can.txt
+++ b/Documentation/networking/can.txt
@@ -372,6 +372,15 @@
     nbytes = sendto(s, &frame, sizeof(struct can_frame),
                     0, (struct sockaddr*)&addr, sizeof(addr));
 
+  An accurate timestamp can be obtained with an ioctl(2) call after reading
+  a message from the socket:
+
+    struct timeval tv;
+    ioctl(s, SIOCGSTAMP, &tv);
+
+  The timestamp has a resolution of one microsecond and is set automatically
+  at the reception of a CAN frame.
+
   Remark about CAN FD (flexible data rate) support:
 
   Generally the handling of CAN FD is very similar to the formerly described
diff --git a/Documentation/sound/alsa/img,spdif-in.txt b/Documentation/sound/alsa/img,spdif-in.txt
new file mode 100644
index 0000000..8b75057
--- /dev/null
+++ b/Documentation/sound/alsa/img,spdif-in.txt
@@ -0,0 +1,49 @@
+The Imagination Technologies SPDIF Input controller contains the following
+controls:
+
+name='IEC958 Capture Mask',index=0
+
+This control returns a mask that shows which of the IEC958 status bits
+can be read using the 'IEC958 Capture Default' control.
+
+name='IEC958 Capture Default',index=0
+
+This control returns the status bits contained within the SPDIF stream that
+is being received. The 'IEC958 Capture Mask' shows which bits can be read
+from this control.
+
+name='SPDIF In Multi Frequency Acquire',index=0
+name='SPDIF In Multi Frequency Acquire',index=1
+name='SPDIF In Multi Frequency Acquire',index=2
+name='SPDIF In Multi Frequency Acquire',index=3
+
+This control is used to attempt acquisition of up to four different sample
+rates. The active rate can be obtained by reading the 'SPDIF In Lock Frequency'
+control.
+
+When the value of this control is set to {0,0,0,0}, the rate given to hw_params
+will determine the single rate the block will capture. Else, the rate given to
+hw_params will be ignored, and the block will attempt capture for each of the
+four sample rates set here.
+
+If less than four rates are required, the same rate can be specified more than
+once
+
+name='SPDIF In Lock Frequency',index=0
+
+This control returns the active capture rate, or 0 if a lock has not been
+acquired
+
+name='SPDIF In Lock TRK',index=0
+
+This control is used to modify the locking/jitter rejection characteristics
+of the block. Larger values increase the locking range, but reduce jitter
+rejection.
+
+name='SPDIF In Lock Acquire Threshold',index=0
+
+This control is used to change the threshold at which a lock is acquired.
+
+name='SPDIF In Lock Release Threshold',index=0
+
+This control is used to change the threshold at which a lock is released.
diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt
index 3049a61..ffd4575 100644
--- a/Documentation/stable_kernel_rules.txt
+++ b/Documentation/stable_kernel_rules.txt
@@ -93,7 +93,7 @@
 Also, some patches may have kernel version prerequisites.  This can be
 specified in the following format in the sign-off area:
 
-     Cc:  <stable@vger.kernel.org> # 3.3.x-
+     Cc: <stable@vger.kernel.org> # 3.3.x-
 
    The tag has the meaning of:
      git cherry-pick <this commit>
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index 10f062e..8c745c8 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -364,6 +364,7 @@
 	accumulates error when temperature is above the desired
 	temperature trip point. For more information see
 	Documentation/thermal/power_allocator.txt
+	Unit: millidegree Celsius
 	RW, Optional
 
 slope
diff --git a/Documentation/vm/slub.txt b/Documentation/vm/slub.txt
index 699d8ea..f0d3409 100644
--- a/Documentation/vm/slub.txt
+++ b/Documentation/vm/slub.txt
@@ -8,7 +8,7 @@
 an impact on overall system performance which may make a bug more
 difficult to find.
 
-In order to switch debugging on one can add a option "slub_debug"
+In order to switch debugging on one can add an option "slub_debug"
 to the kernel command line. That will enable full debugging for
 all slabs.
 
diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt
index d8b0d33..55120a0 100644
--- a/Documentation/watchdog/watchdog-kernel-api.txt
+++ b/Documentation/watchdog/watchdog-kernel-api.txt
@@ -44,17 +44,18 @@
 
 struct watchdog_device {
 	int id;
-	struct cdev cdev;
-	struct device *dev;
 	struct device *parent;
+	const struct attribute_group **groups;
 	const struct watchdog_info *info;
 	const struct watchdog_ops *ops;
 	unsigned int bootstatus;
 	unsigned int timeout;
 	unsigned int min_timeout;
 	unsigned int max_timeout;
+	struct notifier_block reboot_nb;
+	struct notifier_block restart_nb;
 	void *driver_data;
-	struct mutex lock;
+	struct watchdog_core_data *wd_data;
 	unsigned long status;
 	struct list_head deferred;
 };
@@ -64,27 +65,32 @@
   /dev/watchdog0 cdev (dynamic major, minor 0) as well as the old
   /dev/watchdog miscdev. The id is set automatically when calling
   watchdog_register_device.
-* cdev: cdev for the dynamic /dev/watchdog<id> device nodes. This
-  field is also populated by watchdog_register_device.
-* dev: device under the watchdog class (created by watchdog_register_device).
 * parent: set this to the parent device (or NULL) before calling
   watchdog_register_device.
+* groups: List of sysfs attribute groups to create when creating the watchdog
+  device.
 * info: a pointer to a watchdog_info structure. This structure gives some
   additional information about the watchdog timer itself. (Like it's unique name)
 * ops: a pointer to the list of watchdog operations that the watchdog supports.
 * timeout: the watchdog timer's timeout value (in seconds).
 * min_timeout: the watchdog timer's minimum timeout value (in seconds).
 * max_timeout: the watchdog timer's maximum timeout value (in seconds).
+* reboot_nb: notifier block that is registered for reboot notifications, for
+  internal use only. If the driver calls watchdog_stop_on_reboot, watchdog core
+  will stop the watchdog on such notifications.
+* restart_nb: notifier block that is registered for machine restart, for
+  internal use only. If a watchdog is capable of restarting the machine, it
+  should define ops->restart. Priority can be changed through
+  watchdog_set_restart_priority.
 * bootstatus: status of the device after booting (reported with watchdog
   WDIOF_* status bits).
 * driver_data: a pointer to the drivers private data of a watchdog device.
   This data should only be accessed via the watchdog_set_drvdata and
   watchdog_get_drvdata routines.
-* lock: Mutex for WatchDog Timer Driver Core internal use only.
+* wd_data: a pointer to watchdog core internal data.
 * status: this field contains a number of status bits that give extra
   information about the status of the device (Like: is the watchdog timer
-  running/active, is the nowayout bit set, is the device opened via
-  the /dev/watchdog interface or not, ...).
+  running/active, or is the nowayout bit set).
 * deferred: entry in wtd_deferred_reg_list which is used to
   register early initialized watchdogs.
 
@@ -100,8 +106,9 @@
 	unsigned int (*status)(struct watchdog_device *);
 	int (*set_timeout)(struct watchdog_device *, unsigned int);
 	unsigned int (*get_timeleft)(struct watchdog_device *);
-	void (*ref)(struct watchdog_device *);
-	void (*unref)(struct watchdog_device *);
+	int (*restart)(struct watchdog_device *);
+	void (*ref)(struct watchdog_device *) __deprecated;
+	void (*unref)(struct watchdog_device *) __deprecated;
 	long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
 };
 
@@ -110,20 +117,6 @@
 the watchdog is active. (This to avoid a system crash when you unload the
 module and /dev/watchdog is still open).
 
-If the watchdog_device struct is dynamically allocated, just locking the module
-is not enough and a driver also needs to define the ref and unref operations to
-ensure the structure holding the watchdog_device does not go away.
-
-The simplest (and usually sufficient) implementation of this is to:
-1) Add a kref struct to the same structure which is holding the watchdog_device
-2) Define a release callback for the kref which frees the struct holding both
-3) Call kref_init on this kref *before* calling watchdog_register_device()
-4) Define a ref operation calling kref_get on this kref
-5) Define a unref operation calling kref_put on this kref
-6) When it is time to cleanup:
- * Do not kfree() the struct holding both, the last kref_put will do this!
- * *After* calling watchdog_unregister_device() call kref_put on the kref
-
 Some operations are mandatory and some are optional. The mandatory operations
 are:
 * start: this is a pointer to the routine that starts the watchdog timer
@@ -164,34 +157,23 @@
   (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the
   watchdog's info structure).
 * get_timeleft: this routines returns the time that's left before a reset.
-* ref: the operation that calls kref_get on the kref of a dynamically
-  allocated watchdog_device struct.
-* unref: the operation that calls kref_put on the kref of a dynamically
-  allocated watchdog_device struct.
+* restart: this routine restarts the machine. It returns 0 on success or a
+  negative errno code for failure.
 * ioctl: if this routine is present then it will be called first before we do
   our own internal ioctl call handling. This routine should return -ENOIOCTLCMD
   if a command is not supported. The parameters that are passed to the ioctl
   call are: watchdog_device, cmd and arg.
 
+The 'ref' and 'unref' operations are no longer used and deprecated.
+
 The status bits should (preferably) be set with the set_bit and clear_bit alike
 bit-operations. The status bits that are defined are:
 * WDOG_ACTIVE: this status bit indicates whether or not a watchdog timer device
   is active or not. When the watchdog is active after booting, then you should
   set this status bit (Note: when you register the watchdog timer device with
   this bit set, then opening /dev/watchdog will skip the start operation)
-* WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device
-  was opened via /dev/watchdog.
-  (This bit should only be used by the WatchDog Timer Driver Core).
-* WDOG_ALLOW_RELEASE: this bit stores whether or not the magic close character
-  has been sent (so that we can support the magic close feature).
-  (This bit should only be used by the WatchDog Timer Driver Core).
 * WDOG_NO_WAY_OUT: this bit stores the nowayout setting for the watchdog.
   If this bit is set then the watchdog timer will not be able to stop.
-* WDOG_UNREGISTERED: this bit gets set by the WatchDog Timer Driver Core
-  after calling watchdog_unregister_device, and then checked before calling
-  any watchdog_ops, so that you can be sure that no operations (other then
-  unref) will get called after unregister, even if userspace still holds a
-  reference to /dev/watchdog
 
   To set the WDOG_NO_WAY_OUT status bit (before registering your watchdog
   timer device) you can either:
@@ -231,3 +213,18 @@
 to set the default timeout value as timeout value in the watchdog_device and
 then use this function to set the user "preferred" timeout value.
 This routine returns zero on success and a negative errno code for failure.
+
+To disable the watchdog on reboot, the user must call the following helper:
+
+static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd);
+
+To change the priority of the restart handler the following helper should be
+used:
+
+void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority);
+
+User should follow the following guidelines for setting the priority:
+* 0: should be called in last resort, has limited restart capabilities
+* 128: default restart handler, use if no other handler is expected to be
+  available, and/or if restart is sufficient to restart the entire system
+* 255: highest priority, will preempt all other restart handlers
diff --git a/MAINTAINERS b/MAINTAINERS
index 04d62b1..d38c324 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -240,6 +240,12 @@
 S:	Maintained
 F:	drivers/hwmon/abituguru3.c
 
+ACCES 104-IDI-48 GPIO DRIVER
+M:	"William Breathitt Gray" <vilhelm.gray@gmail.com>
+L:	linux-gpio@vger.kernel.org
+S:	Maintained
+F:	drivers/gpio/gpio-104-idi-48.c
+
 ACCES 104-IDIO-16 GPIO DRIVER
 M:	"William Breathitt Gray" <vilhelm.gray@gmail.com>
 L:	linux-gpio@vger.kernel.org
@@ -7821,11 +7827,12 @@
 F:	arch/arm/*omap*/usb*
 
 OMAP GPIO DRIVER
-M:	Javier Martinez Canillas <javier@dowhile0.org>
+M:	Grygorii Strashko <grygorii.strashko@ti.com>
 M:	Santosh Shilimkar <ssantosh@kernel.org>
 M:	Kevin Hilman <khilman@deeprootsystems.com>
 L:	linux-omap@vger.kernel.org
 S:	Maintained
+F:	Documentation/devicetree/bindings/gpio/gpio-omap.txt
 F:	drivers/gpio/gpio-omap.c
 
 OMAP/NEWFLOW NANOBONE MACHINE SUPPORT
@@ -8685,6 +8692,12 @@
 F:	sound/arm/pxa*
 F:	sound/soc/pxa/
 
+PXA GPIO DRIVER
+M:	Robert Jarzmik <robert.jarzmik@free.fr>
+L:	linux-gpio@vger.kernel.org
+S:	Maintained
+F:	drivers/gpio/gpio-pxa.c
+
 PXA3xx NAND FLASH DRIVER
 M:	Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
 L:	linux-mtd@lists.infradead.org
@@ -11676,6 +11689,7 @@
 
 WATCHDOG DEVICE DRIVERS
 M:	Wim Van Sebroeck <wim@iguana.be>
+R:	Guenter Roeck <linux@roeck-us.net>
 L:	linux-watchdog@vger.kernel.org
 W:	http://www.linux-watchdog.org/
 T:	git git://www.linux-watchdog.org/linux-watchdog.git
diff --git a/arch/arm/mach-clps711x/board-autcpu12.c b/arch/arm/mach-clps711x/board-autcpu12.c
index c3d9642..ba3d7d1 100644
--- a/arch/arm/mach-clps711x/board-autcpu12.c
+++ b/arch/arm/mach-clps711x/board-autcpu12.c
@@ -31,7 +31,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand-gpio.h>
 #include <linux/platform_device.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
 
 #include <mach/hardware.h>
 #include <asm/sizes.h>
diff --git a/arch/arm/mach-clps711x/board-p720t.c b/arch/arm/mach-clps711x/board-p720t.c
index e68dd62..80a16a8 100644
--- a/arch/arm/mach-clps711x/board-p720t.c
+++ b/arch/arm/mach-clps711x/board-p720t.c
@@ -28,7 +28,7 @@
 #include <linux/leds.h>
 #include <linux/sizes.h>
 #include <linux/backlight.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand-gpio.h>
diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c
index 703ce31..9986f9a 100644
--- a/arch/arm/mach-imx/mach-mx21ads.c
+++ b/arch/arm/mach-imx/mach-mx21ads.c
@@ -17,7 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/physmap.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/gpio.h>
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
index a95499e..97e6655 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -11,7 +11,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index acb60ed..d058125 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -225,5 +225,9 @@
 	if (omap_rev() == OMAP3430_REV_ES1_0)
 		features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM;
 
+	/* Errata I810 for omap5 / dra7 */
+	if (soc_is_omap54xx() || soc_is_dra7xx())
+		features.flags |= TI_CLK_ERRATA_I810;
+
 	ti_clk_setup_features(&features);
 }
diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c
index ff780a8..b577833 100644
--- a/arch/arm/mach-s3c64xx/dev-audio.c
+++ b/arch/arm/mach-s3c64xx/dev-audio.c
@@ -54,12 +54,13 @@
 
 static struct resource s3c64xx_iis0_resource[] = {
 	[0] = DEFINE_RES_MEM(S3C64XX_PA_IIS0, SZ_256),
-	[1] = DEFINE_RES_DMA(DMACH_I2S0_OUT),
-	[2] = DEFINE_RES_DMA(DMACH_I2S0_IN),
 };
 
-static struct s3c_audio_pdata i2sv3_pdata = {
+static struct s3c_audio_pdata i2s0_pdata = {
 	.cfg_gpio = s3c64xx_i2s_cfg_gpio,
+	.dma_filter = pl08x_filter_id,
+	.dma_playback = DMACH_I2S0_OUT,
+	.dma_capture = DMACH_I2S0_IN,
 };
 
 struct platform_device s3c64xx_device_iis0 = {
@@ -68,15 +69,20 @@
 	.num_resources	  = ARRAY_SIZE(s3c64xx_iis0_resource),
 	.resource	  = s3c64xx_iis0_resource,
 	.dev = {
-		.platform_data = &i2sv3_pdata,
+		.platform_data = &i2s0_pdata,
 	},
 };
 EXPORT_SYMBOL(s3c64xx_device_iis0);
 
 static struct resource s3c64xx_iis1_resource[] = {
 	[0] = DEFINE_RES_MEM(S3C64XX_PA_IIS1, SZ_256),
-	[1] = DEFINE_RES_DMA(DMACH_I2S1_OUT),
-	[2] = DEFINE_RES_DMA(DMACH_I2S1_IN),
+};
+
+static struct s3c_audio_pdata i2s1_pdata = {
+	.cfg_gpio = s3c64xx_i2s_cfg_gpio,
+	.dma_filter = pl08x_filter_id,
+	.dma_playback = DMACH_I2S1_OUT,
+	.dma_capture = DMACH_I2S1_IN,
 };
 
 struct platform_device s3c64xx_device_iis1 = {
@@ -85,19 +91,20 @@
 	.num_resources	  = ARRAY_SIZE(s3c64xx_iis1_resource),
 	.resource	  = s3c64xx_iis1_resource,
 	.dev = {
-		.platform_data = &i2sv3_pdata,
+		.platform_data = &i2s1_pdata,
 	},
 };
 EXPORT_SYMBOL(s3c64xx_device_iis1);
 
 static struct resource s3c64xx_iisv4_resource[] = {
 	[0] = DEFINE_RES_MEM(S3C64XX_PA_IISV4, SZ_256),
-	[1] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_TX),
-	[2] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_RX),
 };
 
 static struct s3c_audio_pdata i2sv4_pdata = {
 	.cfg_gpio = s3c64xx_i2s_cfg_gpio,
+	.dma_filter = pl08x_filter_id,
+	.dma_playback = DMACH_HSI_I2SV40_TX,
+	.dma_capture = DMACH_HSI_I2SV40_RX,
 	.type = {
 		.i2s = {
 			.quirks = QUIRK_PRI_6CHAN,
@@ -142,12 +149,13 @@
 
 static struct resource s3c64xx_pcm0_resource[] = {
 	[0] = DEFINE_RES_MEM(S3C64XX_PA_PCM0, SZ_256),
-	[1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
-	[2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
 };
 
 static struct s3c_audio_pdata s3c_pcm0_pdata = {
 	.cfg_gpio = s3c64xx_pcm_cfg_gpio,
+	.dma_filter = pl08x_filter_id,
+	.dma_capture = DMACH_PCM0_RX,
+	.dma_playback = DMACH_PCM0_TX,
 };
 
 struct platform_device s3c64xx_device_pcm0 = {
@@ -163,12 +171,13 @@
 
 static struct resource s3c64xx_pcm1_resource[] = {
 	[0] = DEFINE_RES_MEM(S3C64XX_PA_PCM1, SZ_256),
-	[1] = DEFINE_RES_DMA(DMACH_PCM1_TX),
-	[2] = DEFINE_RES_DMA(DMACH_PCM1_RX),
 };
 
 static struct s3c_audio_pdata s3c_pcm1_pdata = {
 	.cfg_gpio = s3c64xx_pcm_cfg_gpio,
+	.dma_filter = pl08x_filter_id,
+	.dma_playback = DMACH_PCM1_TX,
+	.dma_capture = DMACH_PCM1_RX,
 };
 
 struct platform_device s3c64xx_device_pcm1 = {
@@ -196,13 +205,15 @@
 
 static struct resource s3c64xx_ac97_resource[] = {
 	[0] = DEFINE_RES_MEM(S3C64XX_PA_AC97, SZ_256),
-	[1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT),
-	[2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN),
-	[3] = DEFINE_RES_DMA(DMACH_AC97_MICIN),
-	[4] = DEFINE_RES_IRQ(IRQ_AC97),
+	[1] = DEFINE_RES_IRQ(IRQ_AC97),
 };
 
-static struct s3c_audio_pdata s3c_ac97_pdata;
+static struct s3c_audio_pdata s3c_ac97_pdata = {
+	.dma_playback = DMACH_AC97_PCMOUT,
+	.dma_filter = pl08x_filter_id,
+	.dma_capture = DMACH_AC97_PCMIN,
+	.dma_capture_mic = DMACH_AC97_MICIN,
+};
 
 static u64 s3c64xx_ac97_dmamask = DMA_BIT_MASK(32);
 
diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h
index 096e140..9c739ea 100644
--- a/arch/arm/mach-s3c64xx/include/mach/dma.h
+++ b/arch/arm/mach-s3c64xx/include/mach/dma.h
@@ -14,38 +14,38 @@
 #define S3C64XX_DMA_CHAN(name)		((unsigned long)(name))
 
 /* DMA0/SDMA0 */
-#define DMACH_UART0		S3C64XX_DMA_CHAN("uart0_tx")
-#define DMACH_UART0_SRC2	S3C64XX_DMA_CHAN("uart0_rx")
-#define DMACH_UART1		S3C64XX_DMA_CHAN("uart1_tx")
-#define DMACH_UART1_SRC2	S3C64XX_DMA_CHAN("uart1_rx")
-#define DMACH_UART2		S3C64XX_DMA_CHAN("uart2_tx")
-#define DMACH_UART2_SRC2	S3C64XX_DMA_CHAN("uart2_rx")
-#define DMACH_UART3		S3C64XX_DMA_CHAN("uart3_tx")
-#define DMACH_UART3_SRC2	S3C64XX_DMA_CHAN("uart3_rx")
-#define DMACH_PCM0_TX		S3C64XX_DMA_CHAN("pcm0_tx")
-#define DMACH_PCM0_RX		S3C64XX_DMA_CHAN("pcm0_rx")
-#define DMACH_I2S0_OUT		S3C64XX_DMA_CHAN("i2s0_tx")
-#define DMACH_I2S0_IN		S3C64XX_DMA_CHAN("i2s0_rx")
+#define DMACH_UART0		"uart0_tx"
+#define DMACH_UART0_SRC2	"uart0_rx"
+#define DMACH_UART1		"uart1_tx"
+#define DMACH_UART1_SRC2	"uart1_rx"
+#define DMACH_UART2		"uart2_tx"
+#define DMACH_UART2_SRC2	"uart2_rx"
+#define DMACH_UART3		"uart3_tx"
+#define DMACH_UART3_SRC2	"uart3_rx"
+#define DMACH_PCM0_TX		"pcm0_tx"
+#define DMACH_PCM0_RX		"pcm0_rx"
+#define DMACH_I2S0_OUT		"i2s0_tx"
+#define DMACH_I2S0_IN		"i2s0_rx"
 #define DMACH_SPI0_TX		S3C64XX_DMA_CHAN("spi0_tx")
 #define DMACH_SPI0_RX		S3C64XX_DMA_CHAN("spi0_rx")
-#define DMACH_HSI_I2SV40_TX	S3C64XX_DMA_CHAN("i2s2_tx")
-#define DMACH_HSI_I2SV40_RX	S3C64XX_DMA_CHAN("i2s2_rx")
+#define DMACH_HSI_I2SV40_TX	"i2s2_tx"
+#define DMACH_HSI_I2SV40_RX	"i2s2_rx"
 
 /* DMA1/SDMA1 */
-#define DMACH_PCM1_TX		S3C64XX_DMA_CHAN("pcm1_tx")
-#define DMACH_PCM1_RX		S3C64XX_DMA_CHAN("pcm1_rx")
-#define DMACH_I2S1_OUT		S3C64XX_DMA_CHAN("i2s1_tx")
-#define DMACH_I2S1_IN		S3C64XX_DMA_CHAN("i2s1_rx")
+#define DMACH_PCM1_TX		"pcm1_tx"
+#define DMACH_PCM1_RX		"pcm1_rx"
+#define DMACH_I2S1_OUT		"i2s1_tx"
+#define DMACH_I2S1_IN		"i2s1_rx"
 #define DMACH_SPI1_TX		S3C64XX_DMA_CHAN("spi1_tx")
 #define DMACH_SPI1_RX		S3C64XX_DMA_CHAN("spi1_rx")
-#define DMACH_AC97_PCMOUT	S3C64XX_DMA_CHAN("ac97_out")
-#define DMACH_AC97_PCMIN	S3C64XX_DMA_CHAN("ac97_in")
-#define DMACH_AC97_MICIN	S3C64XX_DMA_CHAN("ac97_mic")
-#define DMACH_PWM		S3C64XX_DMA_CHAN("pwm")
-#define DMACH_IRDA		S3C64XX_DMA_CHAN("irda")
-#define DMACH_EXTERNAL		S3C64XX_DMA_CHAN("external")
-#define DMACH_SECURITY_RX	S3C64XX_DMA_CHAN("sec_rx")
-#define DMACH_SECURITY_TX	S3C64XX_DMA_CHAN("sec_tx")
+#define DMACH_AC97_PCMOUT	"ac97_out"
+#define DMACH_AC97_PCMIN	"ac97_in"
+#define DMACH_AC97_MICIN	"ac97_mic"
+#define DMACH_PWM		"pwm"
+#define DMACH_IRDA		"irda"
+#define DMACH_EXTERNAL		"external"
+#define DMACH_SECURITY_RX	"sec_rx"
+#define DMACH_SECURITY_TX	"sec_tx"
 
 enum dma_ch {
 	DMACH_MAX = 32
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c
index f776adc..723f47f 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410.c
@@ -29,7 +29,7 @@
 #include <linux/pwm_backlight.h>
 #include <linux/dm9000.h>
 #include <linux/gpio_keys.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/spi/spi.h>
 
 #include <linux/platform_data/pca953x.h>
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 42f6f9c..f39938f 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -65,6 +65,7 @@
 #include <linux/platform_data/usb-ohci-s3c2410.h>
 #include <plat/usb-phy.h>
 #include <plat/regs-spi.h>
+#include <linux/platform_data/asoc-s3c.h>
 #include <linux/platform_data/spi-s3c64xx.h>
 
 static u64 samsung_device_dma_mask = DMA_BIT_MASK(32);
@@ -74,9 +75,15 @@
 static struct resource s3c_ac97_resource[] = {
 	[0] = DEFINE_RES_MEM(S3C2440_PA_AC97, S3C2440_SZ_AC97),
 	[1] = DEFINE_RES_IRQ(IRQ_S3C244X_AC97),
-	[2] = DEFINE_RES_DMA_NAMED(DMACH_PCM_OUT, "PCM out"),
-	[3] = DEFINE_RES_DMA_NAMED(DMACH_PCM_IN, "PCM in"),
-	[4] = DEFINE_RES_DMA_NAMED(DMACH_MIC_IN, "Mic in"),
+};
+
+static struct s3c_audio_pdata s3c_ac97_pdata = {
+#ifdef CONFIG_S3C24XX_DMAC
+	.dma_filter = s3c24xx_dma_filter,
+#endif
+	.dma_playback = (void *)DMACH_PCM_OUT,
+	.dma_capture = (void *)DMACH_PCM_IN,
+	.dma_capture_mic = (void *)DMACH_MIC_IN,
 };
 
 struct platform_device s3c_device_ac97 = {
@@ -87,6 +94,7 @@
 	.dev		= {
 		.dma_mask		= &samsung_device_dma_mask,
 		.coherent_dma_mask	= DMA_BIT_MASK(32),
+		.platform_data		= &s3c_ac97_pdata,
 	}
 };
 #endif /* CONFIG_CPU_S3C2440 */
@@ -566,6 +574,14 @@
 	[0] = DEFINE_RES_MEM(S3C24XX_PA_IIS, S3C24XX_SZ_IIS),
 };
 
+static struct s3c_audio_pdata s3c_iis_platdata = {
+#ifdef CONFIG_S3C24XX_DMAC
+	.dma_filter = s3c24xx_dma_filter,
+#endif
+	.dma_playback = (void *)DMACH_I2S_OUT,
+	.dma_capture = (void *)DMACH_I2S_IN,
+};
+
 struct platform_device s3c_device_iis = {
 	.name		= "s3c24xx-iis",
 	.id		= -1,
@@ -574,6 +590,7 @@
 	.dev		= {
 		.dma_mask		= &samsung_device_dma_mask,
 		.coherent_dma_mask	= DMA_BIT_MASK(32),
+		.platform_data		= &s3c_iis_platdata,
 	}
 };
 #endif /* CONFIG_PLAT_S3C24XX */
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c
index 4f61378..5020057 100644
--- a/arch/avr32/mach-at32ap/pio.c
+++ b/arch/avr32/mach-at32ap/pio.c
@@ -203,7 +203,7 @@
 
 static int direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct pio_device *pio = container_of(chip, struct pio_device, chip);
+	struct pio_device *pio = gpiochip_get_data(chip);
 	u32 mask = 1 << offset;
 
 	if (!(pio_readl(pio, PSR) & mask))
@@ -215,7 +215,7 @@
 
 static int gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct pio_device *pio = container_of(chip, struct pio_device, chip);
+	struct pio_device *pio = gpiochip_get_data(chip);
 
 	return (pio_readl(pio, PDSR) >> offset) & 1;
 }
@@ -224,7 +224,7 @@
 
 static int direction_output(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct pio_device *pio = container_of(chip, struct pio_device, chip);
+	struct pio_device *pio = gpiochip_get_data(chip);
 	u32 mask = 1 << offset;
 
 	if (!(pio_readl(pio, PSR) & mask))
@@ -237,7 +237,7 @@
 
 static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct pio_device *pio = container_of(chip, struct pio_device, chip);
+	struct pio_device *pio = gpiochip_get_data(chip);
 	u32 mask = 1 << offset;
 
 	if (value)
@@ -335,7 +335,7 @@
  */
 static void pio_bank_show(struct seq_file *s, struct gpio_chip *chip)
 {
-	struct pio_device *pio = container_of(chip, struct pio_device, chip);
+	struct pio_device *pio = gpiochip_get_data(chip);
 	u32			psr, osr, imr, pdsr, pusr, ifsr, mdsr;
 	unsigned		i;
 	u32			mask;
@@ -397,7 +397,7 @@
 	pio->chip.label = pio->name;
 	pio->chip.base = pdev->id * 32;
 	pio->chip.ngpio = 32;
-	pio->chip.dev = &pdev->dev;
+	pio->chip.parent = &pdev->dev;
 	pio->chip.owner = THIS_MODULE;
 
 	pio->chip.direction_input = direction_input;
@@ -406,7 +406,7 @@
 	pio->chip.set = gpio_set;
 	pio->chip.dbg_show = pio_bank_show;
 
-	gpiochip_add(&pio->chip);
+	gpiochip_add_data(&pio->chip, pio);
 
 	gpio_irq_setup(pio, irq, gpio_irq_base);
 
diff --git a/arch/x86/include/asm/platform_sst_audio.h b/arch/x86/include/asm/platform_sst_audio.h
index 7249e6d..5973a2f 100644
--- a/arch/x86/include/asm/platform_sst_audio.h
+++ b/arch/x86/include/asm/platform_sst_audio.h
@@ -55,6 +55,7 @@
 	PIPE_MEDIA0_IN = 0x8F,
 	PIPE_MEDIA1_IN = 0x90,
 	PIPE_MEDIA2_IN = 0x91,
+	PIPE_MEDIA3_IN = 0x9C,
 	PIPE_RSVD = 0xFF,
 };
 
diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index db9a675..bca14c8 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -547,6 +547,7 @@
 	INTEL_CHV_IDS(&chv_stolen_funcs),
 	INTEL_SKL_IDS(&gen9_stolen_funcs),
 	INTEL_BXT_IDS(&gen9_stolen_funcs),
+	INTEL_KBL_IDS(&gen9_stolen_funcs),
 };
 
 static void __init intel_graphics_stolen(int num, int slot, int func)
diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c
index 504899a7..98067f7 100644
--- a/drivers/bcma/driver_gpio.c
+++ b/drivers/bcma/driver_gpio.c
@@ -17,14 +17,9 @@
 
 #define BCMA_GPIO_MAX_PINS	32
 
-static inline struct bcma_drv_cc *bcma_gpio_get_cc(struct gpio_chip *chip)
-{
-	return container_of(chip, struct bcma_drv_cc, gpio);
-}
-
 static int bcma_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
 {
-	struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+	struct bcma_drv_cc *cc = gpiochip_get_data(chip);
 
 	return !!bcma_chipco_gpio_in(cc, 1 << gpio);
 }
@@ -32,14 +27,14 @@
 static void bcma_gpio_set_value(struct gpio_chip *chip, unsigned gpio,
 				int value)
 {
-	struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+	struct bcma_drv_cc *cc = gpiochip_get_data(chip);
 
 	bcma_chipco_gpio_out(cc, 1 << gpio, value ? 1 << gpio : 0);
 }
 
 static int bcma_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
 {
-	struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+	struct bcma_drv_cc *cc = gpiochip_get_data(chip);
 
 	bcma_chipco_gpio_outen(cc, 1 << gpio, 0);
 	return 0;
@@ -48,7 +43,7 @@
 static int bcma_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
 				      int value)
 {
-	struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+	struct bcma_drv_cc *cc = gpiochip_get_data(chip);
 
 	bcma_chipco_gpio_outen(cc, 1 << gpio, 1 << gpio);
 	bcma_chipco_gpio_out(cc, 1 << gpio, value ? 1 << gpio : 0);
@@ -57,7 +52,7 @@
 
 static int bcma_gpio_request(struct gpio_chip *chip, unsigned gpio)
 {
-	struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+	struct bcma_drv_cc *cc = gpiochip_get_data(chip);
 
 	bcma_chipco_gpio_control(cc, 1 << gpio, 0);
 	/* clear pulldown */
@@ -70,7 +65,7 @@
 
 static void bcma_gpio_free(struct gpio_chip *chip, unsigned gpio)
 {
-	struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+	struct bcma_drv_cc *cc = gpiochip_get_data(chip);
 
 	/* clear pullup */
 	bcma_chipco_gpio_pullup(cc, 1 << gpio, 0);
@@ -81,7 +76,7 @@
 static void bcma_gpio_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct bcma_drv_cc *cc = bcma_gpio_get_cc(gc);
+	struct bcma_drv_cc *cc = gpiochip_get_data(gc);
 	int gpio = irqd_to_hwirq(d);
 	u32 val = bcma_chipco_gpio_in(cc, BIT(gpio));
 
@@ -92,7 +87,7 @@
 static void bcma_gpio_irq_mask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct bcma_drv_cc *cc = bcma_gpio_get_cc(gc);
+	struct bcma_drv_cc *cc = gpiochip_get_data(gc);
 	int gpio = irqd_to_hwirq(d);
 
 	bcma_chipco_gpio_intmask(cc, BIT(gpio), 0);
@@ -188,7 +183,7 @@
 	chip->direction_input	= bcma_gpio_direction_input;
 	chip->direction_output	= bcma_gpio_direction_output;
 	chip->owner		= THIS_MODULE;
-	chip->dev		= bcma_bus_get_host_dev(bus);
+	chip->parent		= bcma_bus_get_host_dev(bus);
 #if IS_BUILTIN(CONFIG_OF)
 	if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
 		chip->of_node	= cc->core->dev.of_node;
@@ -216,7 +211,7 @@
 	else
 		chip->base		= -1;
 
-	err = gpiochip_add(chip);
+	err = gpiochip_add_data(chip, cc);
 	if (err)
 		return err;
 
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c3e3a02..eca8e01 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -116,6 +116,12 @@
 	  Given a target output frequency, the driver will set the PLL and
 	  divider to best approximate the desired output.
 
+config COMMON_CLK_CS2000_CP
+	tristate "Clock driver for CS2000 Fractional-N Clock Synthesizer & Clock Multiplier"
+	depends on I2C
+	help
+	  If you say yes here you get support for the CS2000 clock multiplier.
+
 config COMMON_CLK_S2MPS11
 	tristate "Clock driver for S2MPS1X/S5M8767 MFD"
 	depends on MFD_SEC_CORE
@@ -161,6 +167,12 @@
           Supports clock drivers for Keystone based SOCs. These SOCs have local
 	  a power sleep control module that gate the clock to the IPs and PLLs.
 
+config COMMON_CLK_NXP
+	def_bool COMMON_CLK && (ARCH_LPC18XX || ARCH_LPC32XX)
+	select REGMAP_MMIO if ARCH_LPC32XX
+	---help---
+	  Support for clock providers on NXP platforms.
+
 config COMMON_CLK_PALMAS
 	tristate "Clock driver for TI Palmas devices"
 	depends on MFD_PALMAS
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 820714c..b038e36 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -21,6 +21,7 @@
 obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN)	+= clk-axi-clkgen.o
 obj-$(CONFIG_ARCH_AXXIA)		+= clk-axm5516.o
 obj-$(CONFIG_COMMON_CLK_CDCE706)	+= clk-cdce706.o
+obj-$(CONFIG_COMMON_CLK_CS2000_CP)	+= clk-cs2000-cp.o
 obj-$(CONFIG_ARCH_CLPS711X)		+= clk-clps711x.o
 obj-$(CONFIG_ARCH_EFM32)		+= clk-efm32gg.o
 obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
@@ -42,6 +43,7 @@
 obj-$(CONFIG_COMMON_CLK_SI570)		+= clk-si570.o
 obj-$(CONFIG_COMMON_CLK_CDCE925)	+= clk-cdce925.o
 obj-$(CONFIG_ARCH_STM32)		+= clk-stm32f4.o
+obj-$(CONFIG_ARCH_TANGOX)		+= clk-tango4.o
 obj-$(CONFIG_CLK_TWL6040)		+= clk-twl6040.o
 obj-$(CONFIG_ARCH_U300)			+= clk-u300.o
 obj-$(CONFIG_ARCH_VT8500)		+= clk-vt8500.o
@@ -62,13 +64,14 @@
 obj-$(CONFIG_PLAT_ORION)		+= mvebu/
 obj-$(CONFIG_ARCH_MESON)		+= meson/
 obj-$(CONFIG_ARCH_MXS)			+= mxs/
-obj-$(CONFIG_ARCH_LPC18XX)		+= nxp/
 obj-$(CONFIG_MACH_PISTACHIO)		+= pistachio/
+obj-$(CONFIG_COMMON_CLK_NXP)		+= nxp/
 obj-$(CONFIG_COMMON_CLK_PXA)		+= pxa/
 obj-$(CONFIG_COMMON_CLK_QCOM)		+= qcom/
 obj-$(CONFIG_ARCH_ROCKCHIP)		+= rockchip/
 obj-$(CONFIG_COMMON_CLK_SAMSUNG)	+= samsung/
 obj-$(CONFIG_ARCH_SHMOBILE_MULTI)	+= shmobile/
+obj-$(CONFIG_ARCH_RENESAS)		+= shmobile/
 obj-$(CONFIG_ARCH_SIRF)			+= sirf/
 obj-$(CONFIG_ARCH_SOCFPGA)		+= socfpga/
 obj-$(CONFIG_PLAT_SPEAR)		+= spear/
diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c
index d0d5076..6f99a53 100644
--- a/drivers/clk/at91/clk-slow.c
+++ b/drivers/clk/at91/clk-slow.c
@@ -10,7 +10,6 @@
  *
  */
 
-#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/slab.h>
@@ -72,8 +71,6 @@
 
 #define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
 
-static struct clk *slow_clk;
-
 static int clk_slow_osc_prepare(struct clk_hw *hw)
 {
 	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
@@ -360,8 +357,6 @@
 	clk = clk_register(NULL, &slowck->hw);
 	if (IS_ERR(clk))
 		kfree(slowck);
-	else
-		slow_clk = clk;
 
 	return clk;
 }
@@ -433,8 +428,6 @@
 	clk = clk_register(NULL, &slowck->hw);
 	if (IS_ERR(clk))
 		kfree(slowck);
-	else
-		slow_clk = clk;
 
 	return clk;
 }
@@ -462,25 +455,3 @@
 
 	of_clk_add_provider(np, of_clk_src_simple_get, clk);
 }
-
-/*
- * FIXME: All slow clk users are not properly claiming it (get + prepare +
- * enable) before using it.
- * If all users properly claiming this clock decide that they don't need it
- * anymore (or are removed), it is disabled while faulty users are still
- * requiring it, and the system hangs.
- * Prevent this clock from being disabled until all users are properly
- * requesting it.
- * Once this is done we should remove this function and the slow_clk variable.
- */
-static int __init of_at91_clk_slow_retain(void)
-{
-	if (!slow_clk)
-		return 0;
-
-	__clk_get(slow_clk);
-	clk_prepare_enable(slow_clk);
-
-	return 0;
-}
-arch_initcall(of_at91_clk_slow_retain);
diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig
index 85260fb..f287845 100644
--- a/drivers/clk/bcm/Kconfig
+++ b/drivers/clk/bcm/Kconfig
@@ -1,3 +1,13 @@
+config CLK_BCM_63XX
+	bool "Broadcom BCM63xx clock support"
+	depends on ARCH_BCM_63XX || COMPILE_TEST
+	depends on COMMON_CLK
+	select COMMON_CLK_IPROC
+	default ARCH_BCM_63XX
+	help
+	  Enable common clock framework support for Broadcom BCM63xx DSL SoCs
+	  based on the ARM architecture
+
 config CLK_BCM_KONA
 	bool "Broadcom Kona CCU clock support"
 	depends on ARCH_BCM_MOBILE || COMPILE_TEST
diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
index 3fc9506..1d79bd2 100644
--- a/drivers/clk/bcm/Makefile
+++ b/drivers/clk/bcm/Makefile
@@ -1,9 +1,11 @@
+obj-$(CONFIG_CLK_BCM_63XX)	+= clk-bcm63xx.o
 obj-$(CONFIG_CLK_BCM_KONA)	+= clk-kona.o
 obj-$(CONFIG_CLK_BCM_KONA)	+= clk-kona-setup.o
 obj-$(CONFIG_CLK_BCM_KONA)	+= clk-bcm281xx.o
 obj-$(CONFIG_CLK_BCM_KONA)	+= clk-bcm21664.o
 obj-$(CONFIG_COMMON_CLK_IPROC)	+= clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
 obj-$(CONFIG_ARCH_BCM2835)	+= clk-bcm2835.o
+obj-$(CONFIG_ARCH_BCM2835)	+= clk-bcm2835-aux.o
 obj-$(CONFIG_COMMON_CLK_IPROC)	+= clk-ns2.o
 obj-$(CONFIG_ARCH_BCM_CYGNUS)	+= clk-cygnus.o
 obj-$(CONFIG_ARCH_BCM_NSP)	+= clk-nsp.o
diff --git a/drivers/clk/bcm/clk-bcm2835-aux.c b/drivers/clk/bcm/clk-bcm2835-aux.c
new file mode 100644
index 0000000..e4f89e2
--- /dev/null
+++ b/drivers/clk/bcm/clk-bcm2835-aux.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/bcm2835.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/clock/bcm2835-aux.h>
+
+#define BCM2835_AUXIRQ		0x00
+#define BCM2835_AUXENB		0x04
+
+static int bcm2835_aux_clk_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct clk_onecell_data *onecell;
+	const char *parent;
+	struct clk *parent_clk;
+	struct resource *res;
+	void __iomem *reg, *gate;
+
+	parent_clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(parent_clk))
+		return PTR_ERR(parent_clk);
+	parent = __clk_get_name(parent_clk);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	reg = devm_ioremap_resource(dev, res);
+	if (!reg)
+		return -ENODEV;
+
+	onecell = devm_kmalloc(dev, sizeof(*onecell), GFP_KERNEL);
+	if (!onecell)
+		return -ENOMEM;
+	onecell->clk_num = BCM2835_AUX_CLOCK_COUNT;
+	onecell->clks = devm_kcalloc(dev, BCM2835_AUX_CLOCK_COUNT,
+				     sizeof(*onecell->clks), GFP_KERNEL);
+	if (!onecell->clks)
+		return -ENOMEM;
+
+	gate = reg + BCM2835_AUXENB;
+	onecell->clks[BCM2835_AUX_CLOCK_UART] =
+		clk_register_gate(dev, "aux_uart", parent, 0, gate, 0, 0, NULL);
+
+	onecell->clks[BCM2835_AUX_CLOCK_SPI1] =
+		clk_register_gate(dev, "aux_spi1", parent, 0, gate, 1, 0, NULL);
+
+	onecell->clks[BCM2835_AUX_CLOCK_SPI2] =
+		clk_register_gate(dev, "aux_spi2", parent, 0, gate, 2, 0, NULL);
+
+	of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get, onecell);
+
+	return 0;
+}
+
+static const struct of_device_id bcm2835_aux_clk_of_match[] = {
+	{ .compatible = "brcm,bcm2835-aux", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, bcm2835_aux_clk_of_match);
+
+static struct platform_driver bcm2835_aux_clk_driver = {
+	.driver = {
+		.name = "bcm2835-aux-clk",
+		.of_match_table = bcm2835_aux_clk_of_match,
+	},
+	.probe          = bcm2835_aux_clk_probe,
+};
+builtin_platform_driver(bcm2835_aux_clk_driver);
+
+MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
+MODULE_DESCRIPTION("BCM2835 auxiliary peripheral clock driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 39bf582..015e687 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -807,6 +807,16 @@
 	.frac_bits = 8,
 };
 
+static const struct bcm2835_clock_data bcm2835_clock_pwm_data = {
+	.name = "pwm",
+	.num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
+	.parents = bcm2835_clock_per_parents,
+	.ctl_reg = CM_PWMCTL,
+	.div_reg = CM_PWMDIV,
+	.int_bits = 12,
+	.frac_bits = 12,
+};
+
 struct bcm2835_pll {
 	struct clk_hw hw;
 	struct bcm2835_cprman *cprman;
@@ -1148,22 +1158,24 @@
 
 static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
 				    unsigned long rate,
-				    unsigned long parent_rate)
+				    unsigned long parent_rate,
+				    bool round_up)
 {
 	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
 	const struct bcm2835_clock_data *data = clock->data;
-	u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
+	u32 unused_frac_mask =
+		GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
 	u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
+	u64 rem;
 	u32 div;
 
-	do_div(temp, rate);
+	rem = do_div(temp, rate);
 	div = temp;
 
-	/* Round and mask off the unused bits */
-	if (unused_frac_mask != 0) {
-		div += unused_frac_mask >> 1;
-		div &= ~unused_frac_mask;
-	}
+	/* Round up and mask off the unused bits */
+	if (round_up && ((div & unused_frac_mask) != 0 || rem != 0))
+		div += unused_frac_mask + 1;
+	div &= ~unused_frac_mask;
 
 	/* Clamp to the limits. */
 	div = max(div, unused_frac_mask + 1);
@@ -1197,16 +1209,6 @@
 	return temp;
 }
 
-static long bcm2835_clock_round_rate(struct clk_hw *hw,
-				     unsigned long rate,
-				     unsigned long *parent_rate)
-{
-	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
-	u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate);
-
-	return bcm2835_clock_rate_from_divisor(clock, *parent_rate, div);
-}
-
 static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw,
 					    unsigned long parent_rate)
 {
@@ -1271,20 +1273,82 @@
 	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
 	struct bcm2835_cprman *cprman = clock->cprman;
 	const struct bcm2835_clock_data *data = clock->data;
-	u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate);
+	u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, false);
 
 	cprman_write(cprman, data->div_reg, div);
 
 	return 0;
 }
 
+static int bcm2835_clock_determine_rate(struct clk_hw *hw,
+		struct clk_rate_request *req)
+{
+	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+	struct clk_hw *parent, *best_parent = NULL;
+	unsigned long rate, best_rate = 0;
+	unsigned long prate, best_prate = 0;
+	size_t i;
+	u32 div;
+
+	/*
+	 * Select parent clock that results in the closest but lower rate
+	 */
+	for (i = 0; i < clk_hw_get_num_parents(hw); ++i) {
+		parent = clk_hw_get_parent_by_index(hw, i);
+		if (!parent)
+			continue;
+		prate = clk_hw_get_rate(parent);
+		div = bcm2835_clock_choose_div(hw, req->rate, prate, true);
+		rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
+		if (rate > best_rate && rate <= req->rate) {
+			best_parent = parent;
+			best_prate = prate;
+			best_rate = rate;
+		}
+	}
+
+	if (!best_parent)
+		return -EINVAL;
+
+	req->best_parent_hw = best_parent;
+	req->best_parent_rate = best_prate;
+
+	req->rate = best_rate;
+
+	return 0;
+}
+
+static int bcm2835_clock_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+	struct bcm2835_cprman *cprman = clock->cprman;
+	const struct bcm2835_clock_data *data = clock->data;
+	u8 src = (index << CM_SRC_SHIFT) & CM_SRC_MASK;
+
+	cprman_write(cprman, data->ctl_reg, src);
+	return 0;
+}
+
+static u8 bcm2835_clock_get_parent(struct clk_hw *hw)
+{
+	struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+	struct bcm2835_cprman *cprman = clock->cprman;
+	const struct bcm2835_clock_data *data = clock->data;
+	u32 src = cprman_read(cprman, data->ctl_reg);
+
+	return (src & CM_SRC_MASK) >> CM_SRC_SHIFT;
+}
+
+
 static const struct clk_ops bcm2835_clock_clk_ops = {
 	.is_prepared = bcm2835_clock_is_on,
 	.prepare = bcm2835_clock_on,
 	.unprepare = bcm2835_clock_off,
 	.recalc_rate = bcm2835_clock_get_rate,
 	.set_rate = bcm2835_clock_set_rate,
-	.round_rate = bcm2835_clock_round_rate,
+	.determine_rate = bcm2835_clock_determine_rate,
+	.set_parent = bcm2835_clock_set_parent,
+	.get_parent = bcm2835_clock_get_parent,
 };
 
 static int bcm2835_vpu_clock_is_on(struct clk_hw *hw)
@@ -1300,7 +1364,9 @@
 	.is_prepared = bcm2835_vpu_clock_is_on,
 	.recalc_rate = bcm2835_clock_get_rate,
 	.set_rate = bcm2835_clock_set_rate,
-	.round_rate = bcm2835_clock_round_rate,
+	.determine_rate = bcm2835_clock_determine_rate,
+	.set_parent = bcm2835_clock_set_parent,
+	.get_parent = bcm2835_clock_get_parent,
 };
 
 static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman,
@@ -1394,45 +1460,23 @@
 {
 	struct bcm2835_clock *clock;
 	struct clk_init_data init;
-	const char *parent;
+	const char *parents[1 << CM_SRC_BITS];
+	size_t i;
 
 	/*
-	 * Most of the clock generators have a mux field, so we
-	 * instantiate a generic mux as our parent to handle it.
+	 * Replace our "xosc" references with the oscillator's
+	 * actual name.
 	 */
-	if (data->num_mux_parents) {
-		const char *parents[1 << CM_SRC_BITS];
-		int i;
-
-		parent = devm_kasprintf(cprman->dev, GFP_KERNEL,
-					"mux_%s", data->name);
-		if (!parent)
-			return NULL;
-
-		/*
-		 * Replace our "xosc" references with the oscillator's
-		 * actual name.
-		 */
-		for (i = 0; i < data->num_mux_parents; i++) {
-			if (strcmp(data->parents[i], "xosc") == 0)
-				parents[i] = cprman->osc_name;
-			else
-				parents[i] = data->parents[i];
-		}
-
-		clk_register_mux(cprman->dev, parent,
-				 parents, data->num_mux_parents,
-				 CLK_SET_RATE_PARENT,
-				 cprman->regs + data->ctl_reg,
-				 CM_SRC_SHIFT, CM_SRC_BITS,
-				 0, &cprman->regs_lock);
-	} else {
-		parent = data->parents[0];
+	for (i = 0; i < data->num_mux_parents; i++) {
+		if (strcmp(data->parents[i], "xosc") == 0)
+			parents[i] = cprman->osc_name;
+		else
+			parents[i] = data->parents[i];
 	}
 
 	memset(&init, 0, sizeof(init));
-	init.parent_names = &parent;
-	init.num_parents = 1;
+	init.parent_names = parents;
+	init.num_parents = data->num_mux_parents;
 	init.name = data->name;
 	init.flags = CLK_IGNORE_UNUSED;
 
@@ -1550,6 +1594,9 @@
 				  cprman->regs + CM_PERIICTL, CM_GATE_BIT,
 				  0, &cprman->regs_lock);
 
+	clks[BCM2835_CLOCK_PWM] =
+		bcm2835_register_clock(cprman, &bcm2835_clock_pwm_data);
+
 	return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
 				   &cprman->onecell);
 }
diff --git a/drivers/clk/bcm/clk-bcm63xx.c b/drivers/clk/bcm/clk-bcm63xx.c
new file mode 100644
index 0000000..fbc17ae
--- /dev/null
+++ b/drivers/clk/bcm/clk-bcm63xx.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/init.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include "clk-iproc.h"
+
+static void __init bcm63138_armpll_init(struct device_node *node)
+{
+	iproc_armpll_setup(node);
+}
+CLK_OF_DECLARE(bcm63138_armpll, "brcm,bcm63138-armpll", bcm63138_armpll_init);
diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c
new file mode 100644
index 0000000..7379de8
--- /dev/null
+++ b/drivers/clk/clk-cs2000-cp.c
@@ -0,0 +1,510 @@
+/*
+ * CS2000  --  CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+
+#define CH_MAX 4
+#define RATIO_REG_SIZE 4
+
+#define DEVICE_ID	0x1
+#define DEVICE_CTRL	0x2
+#define DEVICE_CFG1	0x3
+#define DEVICE_CFG2	0x4
+#define GLOBAL_CFG	0x5
+#define Ratio_Add(x, nth)	(6 + (x * 4) + (nth))
+#define Ratio_Val(x, nth)	((x >> (24 - (8 * nth))) & 0xFF)
+#define Val_Ratio(x, nth)	((x & 0xFF) << (24 - (8 * nth)))
+#define FUNC_CFG1	0x16
+#define FUNC_CFG2	0x17
+
+/* DEVICE_ID */
+#define REVISION_MASK	(0x7)
+#define REVISION_B2_B3	(0x4)
+#define REVISION_C1	(0x6)
+
+/* DEVICE_CTRL */
+#define PLL_UNLOCK	(1 << 7)
+
+/* DEVICE_CFG1 */
+#define RSEL(x)		(((x) & 0x3) << 3)
+#define RSEL_MASK	RSEL(0x3)
+#define ENDEV1		(0x1)
+
+/* GLOBAL_CFG */
+#define ENDEV2		(0x1)
+
+#define CH_SIZE_ERR(ch)		((ch < 0) || (ch >= CH_MAX))
+#define hw_to_priv(_hw)		container_of(_hw, struct cs2000_priv, hw)
+#define priv_to_client(priv)	(priv->client)
+#define priv_to_dev(priv)	(&(priv_to_client(priv)->dev))
+
+#define CLK_IN	0
+#define REF_CLK	1
+#define CLK_MAX 2
+
+struct cs2000_priv {
+	struct clk_hw hw;
+	struct i2c_client *client;
+	struct clk *clk_in;
+	struct clk *ref_clk;
+	struct clk *clk_out;
+};
+
+static const struct of_device_id cs2000_of_match[] = {
+	{ .compatible = "cirrus,cs2000-cp", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, cs2000_of_match);
+
+static const struct i2c_device_id cs2000_id[] = {
+	{ "cs2000-cp", },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, cs2000_id);
+
+#define cs2000_read(priv, addr) \
+	i2c_smbus_read_byte_data(priv_to_client(priv), addr)
+#define cs2000_write(priv, addr, val) \
+	i2c_smbus_write_byte_data(priv_to_client(priv), addr, val)
+
+static int cs2000_bset(struct cs2000_priv *priv, u8 addr, u8 mask, u8 val)
+{
+	s32 data;
+
+	data = cs2000_read(priv, addr);
+	if (data < 0)
+		return data;
+
+	data &= ~mask;
+	data |= (val & mask);
+
+	return cs2000_write(priv, addr, data);
+}
+
+static int cs2000_enable_dev_config(struct cs2000_priv *priv, bool enable)
+{
+	int ret;
+
+	ret = cs2000_bset(priv, DEVICE_CFG1, ENDEV1,
+			  enable ? ENDEV1 : 0);
+	if (ret < 0)
+		return ret;
+
+	ret = cs2000_bset(priv, GLOBAL_CFG,  ENDEV2,
+			  enable ? ENDEV2 : 0);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int cs2000_clk_in_bound_rate(struct cs2000_priv *priv,
+				    u32 rate_in)
+{
+	u32 val;
+
+	if (rate_in >= 32000000 && rate_in < 56000000)
+		val = 0x0;
+	else if (rate_in >= 16000000 && rate_in < 28000000)
+		val = 0x1;
+	else if (rate_in >= 8000000 && rate_in < 14000000)
+		val = 0x2;
+	else
+		return -EINVAL;
+
+	return cs2000_bset(priv, FUNC_CFG1, 0x3 << 3, val << 3);
+}
+
+static int cs2000_wait_pll_lock(struct cs2000_priv *priv)
+{
+	struct device *dev = priv_to_dev(priv);
+	s32 val;
+	unsigned int i;
+
+	for (i = 0; i < 256; i++) {
+		val = cs2000_read(priv, DEVICE_CTRL);
+		if (val < 0)
+			return val;
+		if (!(val & PLL_UNLOCK))
+			return 0;
+		udelay(1);
+	}
+
+	dev_err(dev, "pll lock failed\n");
+
+	return -ETIMEDOUT;
+}
+
+static int cs2000_clk_out_enable(struct cs2000_priv *priv, bool enable)
+{
+	/* enable both AUX_OUT, CLK_OUT */
+	return cs2000_write(priv, DEVICE_CTRL, enable ? 0 : 0x3);
+}
+
+static u32 cs2000_rate_to_ratio(u32 rate_in, u32 rate_out)
+{
+	u64 ratio;
+
+	/*
+	 * ratio = rate_out / rate_in * 2^20
+	 *
+	 * To avoid over flow, rate_out is u64.
+	 * The result should be u32.
+	 */
+	ratio = (u64)rate_out << 20;
+	do_div(ratio, rate_in);
+
+	return ratio;
+}
+
+static unsigned long cs2000_ratio_to_rate(u32 ratio, u32 rate_in)
+{
+	u64 rate_out;
+
+	/*
+	 * ratio = rate_out / rate_in * 2^20
+	 *
+	 * To avoid over flow, rate_out is u64.
+	 * The result should be u32 or unsigned long.
+	 */
+
+	rate_out = (u64)ratio * rate_in;
+	return rate_out >> 20;
+}
+
+static int cs2000_ratio_set(struct cs2000_priv *priv,
+			    int ch, u32 rate_in, u32 rate_out)
+{
+	u32 val;
+	unsigned int i;
+	int ret;
+
+	if (CH_SIZE_ERR(ch))
+		return -EINVAL;
+
+	val = cs2000_rate_to_ratio(rate_in, rate_out);
+	for (i = 0; i < RATIO_REG_SIZE; i++) {
+		ret = cs2000_write(priv,
+				   Ratio_Add(ch, i),
+				   Ratio_Val(val, i));
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static u32 cs2000_ratio_get(struct cs2000_priv *priv, int ch)
+{
+	s32 tmp;
+	u32 val;
+	unsigned int i;
+
+	val = 0;
+	for (i = 0; i < RATIO_REG_SIZE; i++) {
+		tmp = cs2000_read(priv, Ratio_Add(ch, i));
+		if (tmp < 0)
+			return 0;
+
+		val |= Val_Ratio(tmp, i);
+	}
+
+	return val;
+}
+
+static int cs2000_ratio_select(struct cs2000_priv *priv, int ch)
+{
+	int ret;
+
+	if (CH_SIZE_ERR(ch))
+		return -EINVAL;
+
+	/*
+	 * FIXME
+	 *
+	 * this driver supports static ratio mode only at this point.
+	 */
+	ret = cs2000_bset(priv, DEVICE_CFG1, RSEL_MASK, RSEL(ch));
+	if (ret < 0)
+		return ret;
+
+	ret = cs2000_write(priv, DEVICE_CFG2, 0x0);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static unsigned long cs2000_recalc_rate(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	struct cs2000_priv *priv = hw_to_priv(hw);
+	int ch = 0; /* it uses ch0 only at this point */
+	u32 ratio;
+
+	ratio = cs2000_ratio_get(priv, ch);
+
+	return cs2000_ratio_to_rate(ratio, parent_rate);
+}
+
+static long cs2000_round_rate(struct clk_hw *hw, unsigned long rate,
+			      unsigned long *parent_rate)
+{
+	u32 ratio;
+
+	ratio = cs2000_rate_to_ratio(*parent_rate, rate);
+
+	return cs2000_ratio_to_rate(ratio, *parent_rate);
+}
+
+static int __cs2000_set_rate(struct cs2000_priv *priv, int ch,
+			     unsigned long rate, unsigned long parent_rate)
+
+{
+	int ret;
+
+	ret = cs2000_clk_in_bound_rate(priv, parent_rate);
+	if (ret < 0)
+		return ret;
+
+	ret = cs2000_ratio_set(priv, ch, parent_rate, rate);
+	if (ret < 0)
+		return ret;
+
+	ret = cs2000_ratio_select(priv, ch);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int cs2000_set_rate(struct clk_hw *hw,
+			   unsigned long rate, unsigned long parent_rate)
+{
+	struct cs2000_priv *priv = hw_to_priv(hw);
+	int ch = 0; /* it uses ch0 only at this point */
+
+	return __cs2000_set_rate(priv, ch, rate, parent_rate);
+}
+
+static int cs2000_enable(struct clk_hw *hw)
+{
+	struct cs2000_priv *priv = hw_to_priv(hw);
+	int ret;
+
+	ret = cs2000_enable_dev_config(priv, true);
+	if (ret < 0)
+		return ret;
+
+	ret = cs2000_clk_out_enable(priv, true);
+	if (ret < 0)
+		return ret;
+
+	ret = cs2000_wait_pll_lock(priv);
+	if (ret < 0)
+		return ret;
+
+	return ret;
+}
+
+static void cs2000_disable(struct clk_hw *hw)
+{
+	struct cs2000_priv *priv = hw_to_priv(hw);
+
+	cs2000_enable_dev_config(priv, false);
+
+	cs2000_clk_out_enable(priv, false);
+}
+
+static u8 cs2000_get_parent(struct clk_hw *hw)
+{
+	/* always return REF_CLK */
+	return REF_CLK;
+}
+
+static const struct clk_ops cs2000_ops = {
+	.get_parent	= cs2000_get_parent,
+	.recalc_rate	= cs2000_recalc_rate,
+	.round_rate	= cs2000_round_rate,
+	.set_rate	= cs2000_set_rate,
+	.prepare	= cs2000_enable,
+	.unprepare	= cs2000_disable,
+};
+
+static int cs2000_clk_get(struct cs2000_priv *priv)
+{
+	struct i2c_client *client = priv_to_client(priv);
+	struct device *dev = &client->dev;
+	struct clk *clk_in, *ref_clk;
+
+	clk_in = devm_clk_get(dev, "clk_in");
+	/* not yet provided */
+	if (IS_ERR(clk_in))
+		return -EPROBE_DEFER;
+
+	ref_clk = devm_clk_get(dev, "ref_clk");
+	/* not yet provided */
+	if (IS_ERR(ref_clk))
+		return -EPROBE_DEFER;
+
+	priv->clk_in	= clk_in;
+	priv->ref_clk	= ref_clk;
+
+	return 0;
+}
+
+static int cs2000_clk_register(struct cs2000_priv *priv)
+{
+	struct device *dev = priv_to_dev(priv);
+	struct device_node *np = dev->of_node;
+	struct clk_init_data init;
+	const char *name = np->name;
+	struct clk *clk;
+	static const char *parent_names[CLK_MAX];
+	int ch = 0; /* it uses ch0 only at this point */
+	int rate;
+	int ret;
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	/*
+	 * set default rate as 1/1.
+	 * otherwise .set_rate which setup ratio
+	 * is never called if user requests 1/1 rate
+	 */
+	rate = clk_get_rate(priv->ref_clk);
+	ret = __cs2000_set_rate(priv, ch, rate, rate);
+	if (ret < 0)
+		return ret;
+
+	parent_names[CLK_IN]	= __clk_get_name(priv->clk_in);
+	parent_names[REF_CLK]	= __clk_get_name(priv->ref_clk);
+
+	init.name		= name;
+	init.ops		= &cs2000_ops;
+	init.flags		= CLK_SET_RATE_GATE;
+	init.parent_names	= parent_names;
+	init.num_parents	= ARRAY_SIZE(parent_names);
+
+	priv->hw.init = &init;
+
+	clk = clk_register(dev, &priv->hw);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (ret < 0) {
+		clk_unregister(clk);
+		return ret;
+	}
+
+	priv->clk_out = clk;
+
+	return 0;
+}
+
+static int cs2000_version_print(struct cs2000_priv *priv)
+{
+	struct i2c_client *client = priv_to_client(priv);
+	struct device *dev = &client->dev;
+	s32 val;
+	const char *revision;
+
+	val = cs2000_read(priv, DEVICE_ID);
+	if (val < 0)
+		return val;
+
+	/* CS2000 should be 0x0 */
+	if (val >> 3)
+		return -EIO;
+
+	switch (val & REVISION_MASK) {
+	case REVISION_B2_B3:
+		revision = "B2 / B3";
+		break;
+	case REVISION_C1:
+		revision = "C1";
+		break;
+	default:
+		return -EIO;
+	}
+
+	dev_info(dev, "revision - %s\n", revision);
+
+	return 0;
+}
+
+static int cs2000_remove(struct i2c_client *client)
+{
+	struct cs2000_priv *priv = i2c_get_clientdata(client);
+	struct device *dev = &client->dev;
+	struct device_node *np = dev->of_node;
+
+	of_clk_del_provider(np);
+
+	clk_unregister(priv->clk_out);
+
+	return 0;
+}
+
+static int cs2000_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct cs2000_priv *priv;
+	struct device *dev = &client->dev;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->client = client;
+	i2c_set_clientdata(client, priv);
+
+	ret = cs2000_clk_get(priv);
+	if (ret < 0)
+		return ret;
+
+	ret = cs2000_clk_register(priv);
+	if (ret < 0)
+		return ret;
+
+	ret = cs2000_version_print(priv);
+	if (ret < 0)
+		goto probe_err;
+
+	return 0;
+
+probe_err:
+	cs2000_remove(client);
+
+	return ret;
+}
+
+static struct i2c_driver cs2000_driver = {
+	.driver = {
+		.name = "cs2000-cp",
+		.of_match_table = cs2000_of_match,
+	},
+	.probe		= cs2000_probe,
+	.remove		= cs2000_remove,
+	.id_table	= cs2000_id,
+};
+
+module_i2c_driver(cs2000_driver);
+
+MODULE_DESCRIPTION("CS2000-CP driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 3ace102..ded3ff4 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -32,13 +32,14 @@
 
 #define div_mask(width)	((1 << (width)) - 1)
 
-static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
+static unsigned int _get_table_maxdiv(const struct clk_div_table *table,
+				      u8 width)
 {
-	unsigned int maxdiv = 0;
+	unsigned int maxdiv = 0, mask = div_mask(width);
 	const struct clk_div_table *clkt;
 
 	for (clkt = table; clkt->div; clkt++)
-		if (clkt->div > maxdiv)
+		if (clkt->div > maxdiv && clkt->val <= mask)
 			maxdiv = clkt->div;
 	return maxdiv;
 }
@@ -62,7 +63,7 @@
 	if (flags & CLK_DIVIDER_POWER_OF_TWO)
 		return 1 << div_mask(width);
 	if (table)
-		return _get_table_maxdiv(table);
+		return _get_table_maxdiv(table, width);
 	return div_mask(width) + 1;
 }
 
diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c
index 335322d..19fed65 100644
--- a/drivers/clk/clk-gpio.c
+++ b/drivers/clk/clk-gpio.c
@@ -264,8 +264,8 @@
 		const char * const *parent_names, u8 num_parents,
 		unsigned gpio, bool active_low)
 {
-	return clk_register_gpio_gate(NULL, name, parent_names[0],
-			gpio, active_low, 0);
+	return clk_register_gpio_gate(NULL, name, parent_names ?
+			parent_names[0] : NULL, gpio, active_low, 0);
 }
 
 static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name,
@@ -287,18 +287,26 @@
 	const char **parent_names;
 	int i, num_parents;
 
+	num_parents = of_clk_get_parent_count(node);
+	if (num_parents < 0)
+		return;
+
 	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return;
 
-	num_parents = of_clk_get_parent_count(node);
+	if (num_parents) {
+		parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
+		if (!parent_names) {
+			kfree(data);
+			return;
+		}
 
-	parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
-	if (!parent_names)
-		return;
-
-	for (i = 0; i < num_parents; i++)
-		parent_names[i] = of_clk_get_parent_name(node, i);
+		for (i = 0; i < num_parents; i++)
+			parent_names[i] = of_clk_get_parent_name(node, i);
+	} else {
+		parent_names = NULL;
+	}
 
 	data->num_parents = num_parents;
 	data->parent_names = parent_names;
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 7129c86..5ed03c8 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -71,10 +71,9 @@
 	u32 val;
 	unsigned long flags = 0;
 
-	if (mux->table)
+	if (mux->table) {
 		index = mux->table[index];
-
-	else {
+	} else {
 		if (mux->flags & CLK_MUX_INDEX_BIT)
 			index = 1 << index;
 
diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c
index e346b22..850316a 100644
--- a/drivers/clk/clk-si5351.c
+++ b/drivers/clk/clk-si5351.c
@@ -1091,6 +1091,13 @@
 	si5351_set_bits(hwdata->drvdata, SI5351_CLK0_CTRL + hwdata->num,
 			SI5351_CLK_POWERDOWN, 0);
 
+	/*
+	 * Do a pll soft reset on both plls, needed in some cases to get
+	 * all outputs running.
+	 */
+	si5351_reg_write(hwdata->drvdata, SI5351_PLL_RESET,
+			 SI5351_PLL_RESET_A | SI5351_PLL_RESET_B);
+
 	dev_dbg(&hwdata->drvdata->client->dev,
 		"%s - %s: rdiv = %u, parent_rate = %lu, rate = %lu\n",
 		__func__, clk_hw_get_name(hw), (1 << rdiv),
diff --git a/drivers/clk/clk-tango4.c b/drivers/clk/clk-tango4.c
new file mode 100644
index 0000000..004ab7d
--- /dev/null
+++ b/drivers/clk/clk-tango4.c
@@ -0,0 +1,61 @@
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+static struct clk *out[2];
+static struct clk_onecell_data clk_data = { out, 2 };
+
+#define SYSCLK_CTRL	0x20
+#define CPUCLK_CTRL	0x24
+#define LEGACY_DIV	0x3c
+
+#define PLL_N(val)	(((val) >>  0) & 0x7f)
+#define PLL_K(val)	(((val) >> 13) & 0x7)
+#define PLL_M(val)	(((val) >> 16) & 0x7)
+#define DIV_INDEX(val)	(((val) >>  8) & 0xf)
+
+static void __init make_pll(int idx, const char *parent, void __iomem *base)
+{
+	char name[8];
+	u32 val, mul, div;
+
+	sprintf(name, "pll%d", idx);
+	val = readl_relaxed(base + idx*8);
+	mul =  PLL_N(val) + 1;
+	div = (PLL_M(val) + 1) << PLL_K(val);
+	clk_register_fixed_factor(NULL, name, parent, 0, mul, div);
+}
+
+static int __init get_div(void __iomem *base)
+{
+	u8 sysclk_tab[16] = { 2, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4 };
+	int idx = DIV_INDEX(readl_relaxed(base + LEGACY_DIV));
+
+	return sysclk_tab[idx];
+}
+
+static void __init tango4_clkgen_setup(struct device_node *np)
+{
+	int div, ret;
+	void __iomem *base = of_iomap(np, 0);
+	const char *parent = of_clk_get_parent_name(np, 0);
+
+	if (!base)
+		panic("%s: invalid address\n", np->full_name);
+
+	make_pll(0, parent, base);
+	make_pll(1, parent, base);
+
+	out[0] = clk_register_divider(NULL, "cpuclk", "pll0", 0,
+			base + CPUCLK_CTRL, 8, 8, CLK_DIVIDER_ONE_BASED, NULL);
+
+	div = readl_relaxed(base + SYSCLK_CTRL) & BIT(23) ? get_div(base) : 4;
+	out[1] = clk_register_fixed_factor(NULL, "sysclk", "pll1", 0, 1, div);
+
+	ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+	if (IS_ERR(out[0]) || IS_ERR(out[1]) || ret < 0)
+		panic("%s: clk registration failed\n", np->full_name);
+}
+CLK_OF_DECLARE(tango4_clkgen, "sigma,tango4-clkgen", tango4_clkgen_setup);
diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c
index 27c0da2..10224b0 100644
--- a/drivers/clk/clk-xgene.c
+++ b/drivers/clk/clk-xgene.c
@@ -351,7 +351,8 @@
 		/* Set new divider */
 		data = xgene_clk_read(pclk->param.divider_reg +
 				pclk->param.reg_divider_offset);
-		data &= ~((1 << pclk->param.reg_divider_width) - 1);
+		data &= ~((1 << pclk->param.reg_divider_width) - 1)
+				<< pclk->param.reg_divider_shift;
 		data |= divider;
 		xgene_clk_write(data, pclk->param.divider_reg +
 					pclk->param.reg_divider_offset);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index f13c3f4..b4db67a 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1443,6 +1443,15 @@
 	else if (core->parent)
 		best_parent_rate = core->parent->rate;
 
+	if (core->flags & CLK_SET_RATE_UNGATE) {
+		unsigned long flags;
+
+		clk_core_prepare(core);
+		flags = clk_enable_lock();
+		clk_core_enable(core);
+		clk_enable_unlock(flags);
+	}
+
 	if (core->new_parent && core->new_parent != core->parent) {
 		old_parent = __clk_set_parent_before(core, core->new_parent);
 		trace_clk_set_parent(core, core->new_parent);
@@ -1469,6 +1478,15 @@
 
 	core->rate = clk_recalc(core, best_parent_rate);
 
+	if (core->flags & CLK_SET_RATE_UNGATE) {
+		unsigned long flags;
+
+		flags = clk_enable_lock();
+		clk_core_disable(core);
+		clk_enable_unlock(flags);
+		clk_core_unprepare(core);
+	}
+
 	if (core->notifier_count && old_rate != core->rate)
 		__clk_notify(core, POST_RATE_CHANGE, old_rate, core->rate);
 
@@ -1944,7 +1962,7 @@
 	if (p == q)
 		return true;
 
-	/* true if clk->core pointers match. Avoid derefing garbage */
+	/* true if clk->core pointers match. Avoid dereferencing garbage */
 	if (!IS_ERR_OR_NULL(p) && !IS_ERR_OR_NULL(q))
 		if (p->core == q->core)
 			return true;
@@ -2482,7 +2500,7 @@
 	struct clk *clk;
 
 	/* This is to allow this function to be chained to others */
-	if (!hw || IS_ERR(hw))
+	if (IS_ERR_OR_NULL(hw))
 		return (struct clk *) hw;
 
 	clk = kzalloc(sizeof(*clk), GFP_KERNEL);
@@ -2806,10 +2824,9 @@
  * re-enter into the clk framework by calling any top-level clk APIs;
  * this will cause a nested prepare_lock mutex.
  *
- * In all notification cases cases (pre, post and abort rate change) the
- * original clock rate is passed to the callback via struct
- * clk_notifier_data.old_rate and the new frequency is passed via struct
- * clk_notifier_data.new_rate.
+ * In all notification cases (pre, post and abort rate change) the original
+ * clock rate is passed to the callback via struct clk_notifier_data.old_rate
+ * and the new frequency is passed via struct clk_notifier_data.new_rate.
  *
  * clk_notifier_register() must be called from non-atomic context.
  * Returns -EINVAL if called with null arguments, -ENOMEM upon
@@ -3062,9 +3079,6 @@
 	int count;
 	struct clk *clk;
 
-	if (index < 0)
-		return NULL;
-
 	rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,
 					&clkspec);
 	if (rc)
@@ -3083,6 +3097,9 @@
 		}
 		count++;
 	}
+	/* We went off the end of 'clock-indices' without finding it */
+	if (prop && !vp)
+		return NULL;
 
 	if (of_property_read_string_index(clkspec.np, "clock-output-names",
 					  index,
diff --git a/drivers/clk/imx/clk-imx25.c b/drivers/clk/imx/clk-imx25.c
index c4c141c..23686f7 100644
--- a/drivers/clk/imx/clk-imx25.c
+++ b/drivers/clk/imx/clk-imx25.c
@@ -96,13 +96,11 @@
 	NULL
 };
 
-static int __init __mx25_clocks_init(unsigned long osc_rate,
-				     void __iomem *ccm_base)
+static int __init __mx25_clocks_init(void __iomem *ccm_base)
 {
 	BUG_ON(!ccm_base);
 
 	clk[dummy] = imx_clk_fixed("dummy", 0);
-	clk[osc] = imx_clk_fixed("osc", osc_rate);
 	clk[mpll] = imx_clk_pllv1(IMX_PLLV1_IMX25, "mpll", "osc", ccm(CCM_MPCTL));
 	clk[upll] = imx_clk_pllv1(IMX_PLLV1_IMX25, "upll", "osc", ccm(CCM_UPCTL));
 	clk[mpll_cpu_3_4] = imx_clk_fixed_factor("mpll_cpu_3_4", "mpll", 3, 4);
@@ -250,22 +248,10 @@
 
 static void __init mx25_clocks_init_dt(struct device_node *np)
 {
-	struct device_node *refnp;
-	unsigned long osc_rate = 24000000;
 	void __iomem *ccm;
 
-	/* retrieve the freqency of fixed clocks from device tree */
-	for_each_compatible_node(refnp, NULL, "fixed-clock") {
-		u32 rate;
-		if (of_property_read_u32(refnp, "clock-frequency", &rate))
-			continue;
-
-		if (of_device_is_compatible(refnp, "fsl,imx-osc"))
-			osc_rate = rate;
-	}
-
 	ccm = of_iomap(np, 0);
-	__mx25_clocks_init(osc_rate, ccm);
+	__mx25_clocks_init(ccm);
 
 	clk_data.clks = clk;
 	clk_data.clk_num = ARRAY_SIZE(clk);
diff --git a/drivers/clk/imx/clk-imx51-imx53.c b/drivers/clk/imx/clk-imx51-imx53.c
index c677034..29d4c44 100644
--- a/drivers/clk/imx/clk-imx51-imx53.c
+++ b/drivers/clk/imx/clk-imx51-imx53.c
@@ -519,10 +519,10 @@
 						mx53_ldb_di0_sel, ARRAY_SIZE(mx53_ldb_di0_sel), CLK_SET_RATE_PARENT);
 	clk[IMX5_CLK_LDB_DI0_GATE]	= imx_clk_gate2("ldb_di0_gate", "ldb_di0_div", MXC_CCM_CCGR6, 28);
 	clk[IMX5_CLK_LDB_DI1_GATE]	= imx_clk_gate2("ldb_di1_gate", "ldb_di1_div", MXC_CCM_CCGR6, 30);
-	clk[IMX5_CLK_IPU_DI0_SEL]	= imx_clk_mux("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,
-						mx53_ipu_di0_sel, ARRAY_SIZE(mx53_ipu_di0_sel));
-	clk[IMX5_CLK_IPU_DI1_SEL]	= imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,
-						mx53_ipu_di1_sel, ARRAY_SIZE(mx53_ipu_di1_sel));
+	clk[IMX5_CLK_IPU_DI0_SEL]	= imx_clk_mux_flags("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,
+						mx53_ipu_di0_sel, ARRAY_SIZE(mx53_ipu_di0_sel), CLK_SET_RATE_PARENT);
+	clk[IMX5_CLK_IPU_DI1_SEL]	= imx_clk_mux_flags("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,
+						mx53_ipu_di1_sel, ARRAY_SIZE(mx53_ipu_di1_sel), CLK_SET_RATE_PARENT);
 	clk[IMX5_CLK_TVE_EXT_SEL]	= imx_clk_mux_flags("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1,
 						mx53_tve_ext_sel, ARRAY_SIZE(mx53_tve_ext_sel), CLK_SET_RATE_PARENT);
 	clk[IMX5_CLK_TVE_GATE]		= imx_clk_gate2("tve_gate", "tve_pred", MXC_CCM_CCGR2, 30);
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index c193508..f0efc6f 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -70,7 +70,8 @@
 static const char *lvds_sels[] = {
 	"dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
 	"pll4_audio", "pll5_video", "pll8_mlb", "enet_ref",
-	"pcie_ref_125m", "sata_ref_100m",
+	"pcie_ref_125m", "sata_ref_100m",  "usbphy1", "usbphy2",
+	"dummy", "dummy", "dummy", "dummy", "osc",
 };
 static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", "lvds2_in", "dummy", };
 static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c
index 01718d0..08692d7 100644
--- a/drivers/clk/imx/clk-imx6ul.c
+++ b/drivers/clk/imx/clk-imx6ul.c
@@ -399,9 +399,7 @@
 	/* mask handshake of mmdc */
 	writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
 
-	for (i = 0; i < ARRAY_SIZE(clks); i++)
-		if (IS_ERR(clks[i]))
-			pr_err("i.MX6UL clk %d: register failed with %ld\n", i, PTR_ERR(clks[i]));
+	imx_check_clocks(clks, ARRAY_SIZE(clks));
 
 	clk_data.clks = clks;
 	clk_data.clk_num = ARRAY_SIZE(clks);
diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index 448ef32..fbb6a8c 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -833,10 +833,13 @@
 
 	clks[IMX7D_GPT_3M_CLK] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
 
-	for (i = 0; i < ARRAY_SIZE(clks); i++)
-		if (IS_ERR(clks[i]))
-			pr_err("i.MX7D clk %d: register failed with %ld\n",
-					i, PTR_ERR(clks[i]));
+	clks[IMX7D_CLK_ARM] = imx_clk_cpu("arm", "arm_a7_root_clk",
+					 clks[IMX7D_ARM_A7_ROOT_CLK],
+					 clks[IMX7D_ARM_A7_ROOT_SRC],
+					 clks[IMX7D_PLL_ARM_MAIN_CLK],
+					 clks[IMX7D_PLL_SYS_MAIN_CLK]);
+
+	imx_check_clocks(clks, ARRAY_SIZE(clks));
 
 	clk_data.clks = clks;
 	clk_data.clk_num = ARRAY_SIZE(clks);
diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
index 6addf8f..c05c43d 100644
--- a/drivers/clk/imx/clk-pllv3.c
+++ b/drivers/clk/imx/clk-pllv3.c
@@ -97,6 +97,16 @@
 	writel_relaxed(val, pll->base);
 }
 
+static int clk_pllv3_is_prepared(struct clk_hw *hw)
+{
+	struct clk_pllv3 *pll = to_clk_pllv3(hw);
+
+	if (readl_relaxed(pll->base) & BM_PLL_LOCK)
+		return 1;
+
+	return 0;
+}
+
 static unsigned long clk_pllv3_recalc_rate(struct clk_hw *hw,
 					   unsigned long parent_rate)
 {
@@ -139,6 +149,7 @@
 static const struct clk_ops clk_pllv3_ops = {
 	.prepare	= clk_pllv3_prepare,
 	.unprepare	= clk_pllv3_unprepare,
+	.is_prepared	= clk_pllv3_is_prepared,
 	.recalc_rate	= clk_pllv3_recalc_rate,
 	.round_rate	= clk_pllv3_round_rate,
 	.set_rate	= clk_pllv3_set_rate,
@@ -193,6 +204,7 @@
 static const struct clk_ops clk_pllv3_sys_ops = {
 	.prepare	= clk_pllv3_prepare,
 	.unprepare	= clk_pllv3_unprepare,
+	.is_prepared	= clk_pllv3_is_prepared,
 	.recalc_rate	= clk_pllv3_sys_recalc_rate,
 	.round_rate	= clk_pllv3_sys_round_rate,
 	.set_rate	= clk_pllv3_sys_set_rate,
@@ -265,6 +277,7 @@
 static const struct clk_ops clk_pllv3_av_ops = {
 	.prepare	= clk_pllv3_prepare,
 	.unprepare	= clk_pllv3_unprepare,
+	.is_prepared	= clk_pllv3_is_prepared,
 	.recalc_rate	= clk_pllv3_av_recalc_rate,
 	.round_rate	= clk_pllv3_av_round_rate,
 	.set_rate	= clk_pllv3_av_set_rate,
@@ -279,6 +292,7 @@
 static const struct clk_ops clk_pllv3_enet_ops = {
 	.prepare	= clk_pllv3_prepare,
 	.unprepare	= clk_pllv3_unprepare,
+	.is_prepared	= clk_pllv3_is_prepared,
 	.recalc_rate	= clk_pllv3_enet_recalc_rate,
 };
 
diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile
index 645ac7e..8866115 100644
--- a/drivers/clk/mvebu/Makefile
+++ b/drivers/clk/mvebu/Makefile
@@ -7,6 +7,6 @@
 obj-$(CONFIG_ARMADA_38X_CLK)	+= armada-38x.o
 obj-$(CONFIG_ARMADA_39X_CLK)	+= armada-39x.o
 obj-$(CONFIG_ARMADA_XP_CLK)	+= armada-xp.o
-obj-$(CONFIG_DOVE_CLK)		+= dove.o
+obj-$(CONFIG_DOVE_CLK)		+= dove.o dove-divider.o
 obj-$(CONFIG_KIRKWOOD_CLK)	+= kirkwood.o
 obj-$(CONFIG_ORION_CLK)		+= orion.o
diff --git a/drivers/clk/mvebu/dove-divider.c b/drivers/clk/mvebu/dove-divider.c
new file mode 100644
index 0000000..d5c5bfa
--- /dev/null
+++ b/drivers/clk/mvebu/dove-divider.c
@@ -0,0 +1,262 @@
+/*
+ * Marvell Dove PMU Core PLL divider driver
+ *
+ * Cleaned up by substantially rewriting, and converted to DT by
+ * Russell King.  Origin is not known.
+ */
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include "dove-divider.h"
+
+struct dove_clk {
+	const char *name;
+	struct clk_hw hw;
+	void __iomem *base;
+	spinlock_t *lock;
+	u8 div_bit_start;
+	u8 div_bit_end;
+	u8 div_bit_load;
+	u8 div_bit_size;
+	u32 *divider_table;
+};
+
+enum {
+	DIV_CTRL0 = 0,
+	DIV_CTRL1 = 4,
+	DIV_CTRL1_N_RESET_MASK = BIT(10),
+};
+
+#define to_dove_clk(hw) container_of(hw, struct dove_clk, hw)
+
+static void dove_load_divider(void __iomem *base, u32 val, u32 mask, u32 load)
+{
+	u32 v;
+
+	v = readl_relaxed(base + DIV_CTRL1) | DIV_CTRL1_N_RESET_MASK;
+	writel_relaxed(v, base + DIV_CTRL1);
+
+	v = (readl_relaxed(base + DIV_CTRL0) & ~(mask | load)) | val;
+	writel_relaxed(v, base + DIV_CTRL0);
+	writel_relaxed(v | load, base + DIV_CTRL0);
+	ndelay(250);
+	writel_relaxed(v, base + DIV_CTRL0);
+}
+
+static unsigned int dove_get_divider(struct dove_clk *dc)
+{
+	unsigned int divider;
+	u32 val;
+
+	val = readl_relaxed(dc->base + DIV_CTRL0);
+	val >>= dc->div_bit_start;
+
+	divider = val & ~(~0 << dc->div_bit_size);
+
+	if (dc->divider_table)
+		divider = dc->divider_table[divider];
+
+	return divider;
+}
+
+static int dove_calc_divider(const struct dove_clk *dc, unsigned long rate,
+			     unsigned long parent_rate, bool set)
+{
+	unsigned int divider, max;
+
+	divider = DIV_ROUND_CLOSEST(parent_rate, rate);
+
+	if (dc->divider_table) {
+		unsigned int i;
+
+		for (i = 0; dc->divider_table[i]; i++)
+			if (divider == dc->divider_table[i]) {
+				divider = i;
+				break;
+			}
+
+		if (!dc->divider_table[i])
+			return -EINVAL;
+	} else {
+		max = 1 << dc->div_bit_size;
+
+		if (set && (divider == 0 || divider >= max))
+			return -EINVAL;
+		if (divider >= max)
+			divider = max - 1;
+		else if (divider == 0)
+			divider = 1;
+	}
+
+	return divider;
+}
+
+static unsigned long dove_recalc_rate(struct clk_hw *hw, unsigned long parent)
+{
+	struct dove_clk *dc = to_dove_clk(hw);
+	unsigned int divider = dove_get_divider(dc);
+	unsigned long rate = DIV_ROUND_CLOSEST(parent, divider);
+
+	pr_debug("%s(): %s divider=%u parent=%lu rate=%lu\n",
+		 __func__, dc->name, divider, parent, rate);
+
+	return rate;
+}
+
+static long dove_round_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long *parent)
+{
+	struct dove_clk *dc = to_dove_clk(hw);
+	unsigned long parent_rate = *parent;
+	int divider;
+
+	divider = dove_calc_divider(dc, rate, parent_rate, false);
+	if (divider < 0)
+		return divider;
+
+	rate = DIV_ROUND_CLOSEST(parent_rate, divider);
+
+	pr_debug("%s(): %s divider=%u parent=%lu rate=%lu\n",
+		 __func__, dc->name, divider, parent_rate, rate);
+
+	return rate;
+}
+
+static int dove_set_clock(struct clk_hw *hw, unsigned long rate,
+			  unsigned long parent_rate)
+{
+	struct dove_clk *dc = to_dove_clk(hw);
+	u32 mask, load, div;
+	int divider;
+
+	divider = dove_calc_divider(dc, rate, parent_rate, true);
+	if (divider < 0)
+		return divider;
+
+	pr_debug("%s(): %s divider=%u parent=%lu rate=%lu\n",
+		 __func__, dc->name, divider, parent_rate, rate);
+
+	div = (u32)divider << dc->div_bit_start;
+	mask = ~(~0 << dc->div_bit_size) << dc->div_bit_start;
+	load = BIT(dc->div_bit_load);
+
+	spin_lock(dc->lock);
+	dove_load_divider(dc->base, div, mask, load);
+	spin_unlock(dc->lock);
+
+	return 0;
+}
+
+static const struct clk_ops dove_divider_ops = {
+	.set_rate	= dove_set_clock,
+	.round_rate	= dove_round_rate,
+	.recalc_rate	= dove_recalc_rate,
+};
+
+static struct clk *clk_register_dove_divider(struct device *dev,
+	struct dove_clk *dc, const char **parent_names, size_t num_parents,
+	void __iomem *base)
+{
+	char name[32];
+	struct clk_init_data init = {
+		.name = name,
+		.ops = &dove_divider_ops,
+		.parent_names = parent_names,
+		.num_parents = num_parents,
+	};
+
+	strlcpy(name, dc->name, sizeof(name));
+
+	dc->hw.init = &init;
+	dc->base = base;
+	dc->div_bit_size = dc->div_bit_end - dc->div_bit_start + 1;
+
+	return clk_register(dev, &dc->hw);
+}
+
+static DEFINE_SPINLOCK(dove_divider_lock);
+
+static u32 axi_divider[] = {-1, 2, 1, 3, 4, 6, 5, 7, 8, 10, 9, 0};
+
+static struct dove_clk dove_hw_clocks[4] = {
+	{
+		.name = "axi",
+		.lock = &dove_divider_lock,
+		.div_bit_start = 1,
+		.div_bit_end = 6,
+		.div_bit_load = 7,
+		.divider_table = axi_divider,
+	}, {
+		.name = "gpu",
+		.lock = &dove_divider_lock,
+		.div_bit_start = 8,
+		.div_bit_end = 13,
+		.div_bit_load = 14,
+	}, {
+		.name = "vmeta",
+		.lock = &dove_divider_lock,
+		.div_bit_start = 15,
+		.div_bit_end = 20,
+		.div_bit_load = 21,
+	}, {
+		.name = "lcd",
+		.lock = &dove_divider_lock,
+		.div_bit_start = 22,
+		.div_bit_end = 27,
+		.div_bit_load = 28,
+	},
+};
+
+static const char *core_pll[] = {
+	"core-pll",
+};
+
+static int dove_divider_init(struct device *dev, void __iomem *base,
+	struct clk **clks)
+{
+	struct clk *clk;
+	int i;
+
+	/*
+	 * Create the core PLL clock.  We treat this as a fixed rate
+	 * clock as we don't know any better, and documentation is sparse.
+	 */
+	clk = clk_register_fixed_rate(dev, core_pll[0], NULL, CLK_IS_ROOT,
+				      2000000000UL);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	for (i = 0; i < ARRAY_SIZE(dove_hw_clocks); i++)
+		clks[i] = clk_register_dove_divider(dev, &dove_hw_clocks[i],
+						    core_pll,
+						    ARRAY_SIZE(core_pll), base);
+
+	return 0;
+}
+
+static struct clk *dove_divider_clocks[4];
+
+static struct clk_onecell_data dove_divider_data = {
+	.clks = dove_divider_clocks,
+	.clk_num = ARRAY_SIZE(dove_divider_clocks),
+};
+
+void __init dove_divider_clk_init(struct device_node *np)
+{
+	void *base;
+
+	base = of_iomap(np, 0);
+	if (WARN_ON(!base))
+		return;
+
+	if (WARN_ON(dove_divider_init(NULL, base, dove_divider_clocks))) {
+		iounmap(base);
+		return;
+	}
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, &dove_divider_data);
+}
diff --git a/drivers/clk/mvebu/dove-divider.h b/drivers/clk/mvebu/dove-divider.h
new file mode 100644
index 0000000..4f2f718
--- /dev/null
+++ b/drivers/clk/mvebu/dove-divider.h
@@ -0,0 +1,6 @@
+#ifndef DOVE_DIVIDER_H
+#define DOVE_DIVIDER_H
+
+void __init dove_divider_clk_init(struct device_node *np);
+
+#endif
diff --git a/drivers/clk/mvebu/dove.c b/drivers/clk/mvebu/dove.c
index b8c2424..59fad95 100644
--- a/drivers/clk/mvebu/dove.c
+++ b/drivers/clk/mvebu/dove.c
@@ -17,6 +17,7 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include "common.h"
+#include "dove-divider.h"
 
 /*
  * Core Clocks
@@ -184,9 +185,14 @@
 {
 	struct device_node *cgnp =
 		of_find_compatible_node(NULL, NULL, "marvell,dove-gating-clock");
+	struct device_node *ddnp =
+		of_find_compatible_node(NULL, NULL, "marvell,dove-divider-clock");
 
 	mvebu_coreclk_setup(np, &dove_coreclks);
 
+	if (ddnp)
+		dove_divider_clk_init(ddnp);
+
 	if (cgnp)
 		mvebu_clk_gating_setup(cgnp, dove_gating_desc);
 }
diff --git a/drivers/clk/nxp/Makefile b/drivers/clk/nxp/Makefile
index 7f608b0..607bd48 100644
--- a/drivers/clk/nxp/Makefile
+++ b/drivers/clk/nxp/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_ARCH_LPC18XX)	+= clk-lpc18xx-cgu.o
 obj-$(CONFIG_ARCH_LPC18XX)	+= clk-lpc18xx-ccu.o
+obj-$(CONFIG_ARCH_LPC32XX)	+= clk-lpc32xx.o
diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c
new file mode 100644
index 0000000..10dd0fd
--- /dev/null
+++ b/drivers/clk/nxp/clk-lpc32xx.c
@@ -0,0 +1,1569 @@
+/*
+ * Copyright 2015 Vladimir Zapolskiy <vz@mleia.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/lpc32xx-clock.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+/* Common bitfield definitions for x397 PLL (lock), USB PLL and HCLK PLL */
+#define PLL_CTRL_ENABLE			BIT(16)
+#define PLL_CTRL_BYPASS			BIT(15)
+#define PLL_CTRL_DIRECT			BIT(14)
+#define PLL_CTRL_FEEDBACK		BIT(13)
+#define PLL_CTRL_POSTDIV		(BIT(12)|BIT(11))
+#define PLL_CTRL_PREDIV			(BIT(10)|BIT(9))
+#define PLL_CTRL_FEEDDIV		(0xFF << 1)
+#define PLL_CTRL_LOCK			BIT(0)
+
+/* Clock registers on System Control Block */
+#define LPC32XX_CLKPWR_DEBUG_CTRL	0x00
+#define LPC32XX_CLKPWR_USB_DIV		0x1C
+#define LPC32XX_CLKPWR_HCLKDIV_CTRL	0x40
+#define LPC32XX_CLKPWR_PWR_CTRL		0x44
+#define LPC32XX_CLKPWR_PLL397_CTRL	0x48
+#define LPC32XX_CLKPWR_OSC_CTRL		0x4C
+#define LPC32XX_CLKPWR_SYSCLK_CTRL	0x50
+#define LPC32XX_CLKPWR_LCDCLK_CTRL	0x54
+#define LPC32XX_CLKPWR_HCLKPLL_CTRL	0x58
+#define LPC32XX_CLKPWR_ADCCLK_CTRL1	0x60
+#define LPC32XX_CLKPWR_USB_CTRL		0x64
+#define LPC32XX_CLKPWR_SSP_CTRL		0x78
+#define LPC32XX_CLKPWR_I2S_CTRL		0x7C
+#define LPC32XX_CLKPWR_MS_CTRL		0x80
+#define LPC32XX_CLKPWR_MACCLK_CTRL	0x90
+#define LPC32XX_CLKPWR_TEST_CLK_CTRL	0xA4
+#define LPC32XX_CLKPWR_I2CCLK_CTRL	0xAC
+#define LPC32XX_CLKPWR_KEYCLK_CTRL	0xB0
+#define LPC32XX_CLKPWR_ADCCLK_CTRL	0xB4
+#define LPC32XX_CLKPWR_PWMCLK_CTRL	0xB8
+#define LPC32XX_CLKPWR_TIMCLK_CTRL	0xBC
+#define LPC32XX_CLKPWR_TIMCLK_CTRL1	0xC0
+#define LPC32XX_CLKPWR_SPI_CTRL		0xC4
+#define LPC32XX_CLKPWR_FLASHCLK_CTRL	0xC8
+#define LPC32XX_CLKPWR_UART3_CLK_CTRL	0xD0
+#define LPC32XX_CLKPWR_UART4_CLK_CTRL	0xD4
+#define LPC32XX_CLKPWR_UART5_CLK_CTRL	0xD8
+#define LPC32XX_CLKPWR_UART6_CLK_CTRL	0xDC
+#define LPC32XX_CLKPWR_IRDA_CLK_CTRL	0xE0
+#define LPC32XX_CLKPWR_UART_CLK_CTRL	0xE4
+#define LPC32XX_CLKPWR_DMA_CLK_CTRL	0xE8
+
+/* Clock registers on USB controller */
+#define LPC32XX_USB_CLK_CTRL		0xF4
+#define LPC32XX_USB_CLK_STS		0xF8
+
+static struct regmap_config lpc32xx_scb_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
+	.max_register = 0x114,
+	.fast_io = true,
+};
+
+static struct regmap *clk_regmap;
+static void __iomem *usb_clk_vbase;
+
+enum {
+	LPC32XX_USB_CLK_OTG = LPC32XX_USB_CLK_HOST + 1,
+	LPC32XX_USB_CLK_AHB,
+
+	LPC32XX_USB_CLK_MAX = LPC32XX_USB_CLK_AHB + 1,
+};
+
+enum {
+	/* Start from the last defined clock in dt bindings */
+	LPC32XX_CLK_ADC_DIV = LPC32XX_CLK_ADC + 1,
+	LPC32XX_CLK_ADC_RTC,
+	LPC32XX_CLK_TEST1,
+	LPC32XX_CLK_TEST2,
+
+	/* System clocks, PLL 397x and HCLK PLL clocks */
+	LPC32XX_CLK_OSC,
+	LPC32XX_CLK_SYS,
+	LPC32XX_CLK_PLL397X,
+	LPC32XX_CLK_HCLK_PLL,
+	LPC32XX_CLK_HCLK_DIV_PERIPH,
+	LPC32XX_CLK_HCLK_DIV,
+	LPC32XX_CLK_HCLK,
+	LPC32XX_CLK_PERIPH,
+	LPC32XX_CLK_ARM,
+	LPC32XX_CLK_ARM_VFP,
+
+	/* USB clocks */
+	LPC32XX_CLK_USB_PLL,
+	LPC32XX_CLK_USB_DIV,
+	LPC32XX_CLK_USB,
+
+	/* Only one control PWR_CTRL[10] for both muxes */
+	LPC32XX_CLK_PERIPH_HCLK_MUX,
+	LPC32XX_CLK_PERIPH_ARM_MUX,
+
+	/* Only one control PWR_CTRL[2] for all three muxes */
+	LPC32XX_CLK_SYSCLK_PERIPH_MUX,
+	LPC32XX_CLK_SYSCLK_HCLK_MUX,
+	LPC32XX_CLK_SYSCLK_ARM_MUX,
+
+	/* Two clock sources external to the driver */
+	LPC32XX_CLK_XTAL_32K,
+	LPC32XX_CLK_XTAL,
+
+	/* Renumbered USB clocks, may have a parent from SCB table */
+	LPC32XX_CLK_USB_OFFSET,
+	LPC32XX_CLK_USB_I2C = LPC32XX_USB_CLK_I2C + LPC32XX_CLK_USB_OFFSET,
+	LPC32XX_CLK_USB_DEV = LPC32XX_USB_CLK_DEVICE + LPC32XX_CLK_USB_OFFSET,
+	LPC32XX_CLK_USB_HOST = LPC32XX_USB_CLK_HOST + LPC32XX_CLK_USB_OFFSET,
+	LPC32XX_CLK_USB_OTG = LPC32XX_USB_CLK_OTG + LPC32XX_CLK_USB_OFFSET,
+	LPC32XX_CLK_USB_AHB = LPC32XX_USB_CLK_AHB + LPC32XX_CLK_USB_OFFSET,
+
+	/* Stub for composite clocks */
+	LPC32XX_CLK__NULL,
+
+	/* Subclocks of composite clocks, clocks above are for CCF */
+	LPC32XX_CLK_PWM1_MUX,
+	LPC32XX_CLK_PWM1_DIV,
+	LPC32XX_CLK_PWM1_GATE,
+	LPC32XX_CLK_PWM2_MUX,
+	LPC32XX_CLK_PWM2_DIV,
+	LPC32XX_CLK_PWM2_GATE,
+	LPC32XX_CLK_UART3_MUX,
+	LPC32XX_CLK_UART3_DIV,
+	LPC32XX_CLK_UART3_GATE,
+	LPC32XX_CLK_UART4_MUX,
+	LPC32XX_CLK_UART4_DIV,
+	LPC32XX_CLK_UART4_GATE,
+	LPC32XX_CLK_UART5_MUX,
+	LPC32XX_CLK_UART5_DIV,
+	LPC32XX_CLK_UART5_GATE,
+	LPC32XX_CLK_UART6_MUX,
+	LPC32XX_CLK_UART6_DIV,
+	LPC32XX_CLK_UART6_GATE,
+	LPC32XX_CLK_TEST1_MUX,
+	LPC32XX_CLK_TEST1_GATE,
+	LPC32XX_CLK_TEST2_MUX,
+	LPC32XX_CLK_TEST2_GATE,
+	LPC32XX_CLK_USB_DIV_DIV,
+	LPC32XX_CLK_USB_DIV_GATE,
+	LPC32XX_CLK_SD_DIV,
+	LPC32XX_CLK_SD_GATE,
+	LPC32XX_CLK_LCD_DIV,
+	LPC32XX_CLK_LCD_GATE,
+
+	LPC32XX_CLK_HW_MAX,
+	LPC32XX_CLK_MAX = LPC32XX_CLK_SYSCLK_ARM_MUX + 1,
+	LPC32XX_CLK_CCF_MAX = LPC32XX_CLK_USB_AHB + 1,
+};
+
+static struct clk *clk[LPC32XX_CLK_MAX];
+static struct clk_onecell_data clk_data = {
+	.clks = clk,
+	.clk_num = LPC32XX_CLK_MAX,
+};
+
+static struct clk *usb_clk[LPC32XX_USB_CLK_MAX];
+static struct clk_onecell_data usb_clk_data = {
+	.clks = usb_clk,
+	.clk_num = LPC32XX_USB_CLK_MAX,
+};
+
+#define LPC32XX_CLK_PARENTS_MAX			5
+
+struct clk_proto_t {
+	const char *name;
+	const u8 parents[LPC32XX_CLK_PARENTS_MAX];
+	u8 num_parents;
+	unsigned long flags;
+};
+
+#define CLK_PREFIX(LITERAL)		LPC32XX_CLK_ ## LITERAL
+#define NUMARGS(...)	(sizeof((int[]){__VA_ARGS__})/sizeof(int))
+
+#define LPC32XX_CLK_DEFINE(_idx, _name, _flags, ...)		\
+	[CLK_PREFIX(_idx)] = {					\
+		.name = _name,					\
+		.flags = _flags,				\
+		.parents = { __VA_ARGS__ },			\
+		.num_parents = NUMARGS(__VA_ARGS__),		\
+	 }
+
+static const struct clk_proto_t clk_proto[LPC32XX_CLK_CCF_MAX] __initconst = {
+	LPC32XX_CLK_DEFINE(XTAL, "xtal", 0x0),
+	LPC32XX_CLK_DEFINE(XTAL_32K, "xtal_32k", 0x0),
+
+	LPC32XX_CLK_DEFINE(RTC, "rtc", 0x0, LPC32XX_CLK_XTAL_32K),
+	LPC32XX_CLK_DEFINE(OSC, "osc", CLK_IGNORE_UNUSED, LPC32XX_CLK_XTAL),
+	LPC32XX_CLK_DEFINE(SYS, "sys", CLK_IGNORE_UNUSED,
+		LPC32XX_CLK_OSC, LPC32XX_CLK_PLL397X),
+	LPC32XX_CLK_DEFINE(PLL397X, "pll_397x", CLK_IGNORE_UNUSED,
+		LPC32XX_CLK_RTC),
+	LPC32XX_CLK_DEFINE(HCLK_PLL, "hclk_pll", CLK_IGNORE_UNUSED,
+		LPC32XX_CLK_SYS),
+	LPC32XX_CLK_DEFINE(HCLK_DIV_PERIPH, "hclk_div_periph",
+		CLK_IGNORE_UNUSED, LPC32XX_CLK_HCLK_PLL),
+	LPC32XX_CLK_DEFINE(HCLK_DIV, "hclk_div", CLK_IGNORE_UNUSED,
+		LPC32XX_CLK_HCLK_PLL),
+	LPC32XX_CLK_DEFINE(HCLK, "hclk", CLK_IGNORE_UNUSED,
+		LPC32XX_CLK_PERIPH_HCLK_MUX),
+	LPC32XX_CLK_DEFINE(PERIPH, "pclk", CLK_IGNORE_UNUSED,
+		LPC32XX_CLK_SYSCLK_PERIPH_MUX),
+	LPC32XX_CLK_DEFINE(ARM, "arm", CLK_IGNORE_UNUSED,
+		LPC32XX_CLK_PERIPH_ARM_MUX),
+
+	LPC32XX_CLK_DEFINE(PERIPH_HCLK_MUX, "periph_hclk_mux",
+		CLK_IGNORE_UNUSED,
+		LPC32XX_CLK_SYSCLK_HCLK_MUX, LPC32XX_CLK_SYSCLK_PERIPH_MUX),
+	LPC32XX_CLK_DEFINE(PERIPH_ARM_MUX, "periph_arm_mux", CLK_IGNORE_UNUSED,
+		LPC32XX_CLK_SYSCLK_ARM_MUX, LPC32XX_CLK_SYSCLK_PERIPH_MUX),
+	LPC32XX_CLK_DEFINE(SYSCLK_PERIPH_MUX, "sysclk_periph_mux",
+		CLK_IGNORE_UNUSED,
+		LPC32XX_CLK_SYS, LPC32XX_CLK_HCLK_DIV_PERIPH),
+	LPC32XX_CLK_DEFINE(SYSCLK_HCLK_MUX, "sysclk_hclk_mux",
+		CLK_IGNORE_UNUSED,
+		LPC32XX_CLK_SYS, LPC32XX_CLK_HCLK_DIV),
+	LPC32XX_CLK_DEFINE(SYSCLK_ARM_MUX, "sysclk_arm_mux", CLK_IGNORE_UNUSED,
+		LPC32XX_CLK_SYS, LPC32XX_CLK_HCLK_PLL),
+
+	LPC32XX_CLK_DEFINE(ARM_VFP, "vfp9", CLK_IGNORE_UNUSED,
+		LPC32XX_CLK_ARM),
+	LPC32XX_CLK_DEFINE(USB_PLL, "usb_pll",
+		CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT, LPC32XX_CLK_USB_DIV),
+	LPC32XX_CLK_DEFINE(USB_DIV, "usb_div", 0x0, LPC32XX_CLK_OSC),
+	LPC32XX_CLK_DEFINE(USB, "usb", 0x0, LPC32XX_CLK_USB_PLL),
+	LPC32XX_CLK_DEFINE(DMA, "dma", 0x0, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(MLC, "mlc", 0x0, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(SLC, "slc", 0x0, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(LCD, "lcd", 0x0, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(MAC, "mac", 0x0, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(SD, "sd", 0x0, LPC32XX_CLK_ARM),
+	LPC32XX_CLK_DEFINE(DDRAM, "ddram", CLK_GET_RATE_NOCACHE,
+		LPC32XX_CLK_SYSCLK_ARM_MUX),
+	LPC32XX_CLK_DEFINE(SSP0, "ssp0", 0x0, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(SSP1, "ssp1", 0x0, LPC32XX_CLK_HCLK),
+
+	/*
+	 * CLK_GET_RATE_NOCACHE is needed, if UART clock is disabled, its
+	 * divider register does not contain information about selected rate.
+	 */
+	LPC32XX_CLK_DEFINE(UART3, "uart3", CLK_GET_RATE_NOCACHE,
+		LPC32XX_CLK_PERIPH, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(UART4, "uart4", CLK_GET_RATE_NOCACHE,
+		LPC32XX_CLK_PERIPH, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(UART5, "uart5", CLK_GET_RATE_NOCACHE,
+		LPC32XX_CLK_PERIPH, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(UART6, "uart6", CLK_GET_RATE_NOCACHE,
+		LPC32XX_CLK_PERIPH, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(IRDA, "irda", 0x0, LPC32XX_CLK_PERIPH),
+	LPC32XX_CLK_DEFINE(I2C1, "i2c1", 0x0, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(I2C2, "i2c2", 0x0, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(TIMER0, "timer0", 0x0, LPC32XX_CLK_PERIPH),
+	LPC32XX_CLK_DEFINE(TIMER1, "timer1", 0x0, LPC32XX_CLK_PERIPH),
+	LPC32XX_CLK_DEFINE(TIMER2, "timer2", 0x0, LPC32XX_CLK_PERIPH),
+	LPC32XX_CLK_DEFINE(TIMER3, "timer3", 0x0, LPC32XX_CLK_PERIPH),
+	LPC32XX_CLK_DEFINE(TIMER4, "timer4", 0x0, LPC32XX_CLK_PERIPH),
+	LPC32XX_CLK_DEFINE(TIMER5, "timer5", 0x0, LPC32XX_CLK_PERIPH),
+	LPC32XX_CLK_DEFINE(WDOG, "watchdog", 0x0, LPC32XX_CLK_PERIPH),
+	LPC32XX_CLK_DEFINE(I2S0, "i2s0", 0x0, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(I2S1, "i2s1", 0x0, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(SPI1, "spi1", 0x0, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(SPI2, "spi2", 0x0, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(MCPWM, "mcpwm", 0x0, LPC32XX_CLK_HCLK),
+	LPC32XX_CLK_DEFINE(HSTIMER, "hstimer", 0x0, LPC32XX_CLK_PERIPH),
+	LPC32XX_CLK_DEFINE(KEY, "key", 0x0, LPC32XX_CLK_RTC),
+	LPC32XX_CLK_DEFINE(PWM1, "pwm1", 0x0,
+		LPC32XX_CLK_RTC, LPC32XX_CLK_PERIPH),
+	LPC32XX_CLK_DEFINE(PWM2, "pwm2", 0x0,
+		LPC32XX_CLK_RTC, LPC32XX_CLK_PERIPH),
+	LPC32XX_CLK_DEFINE(ADC, "adc", 0x0,
+		LPC32XX_CLK_ADC_RTC, LPC32XX_CLK_ADC_DIV),
+	LPC32XX_CLK_DEFINE(ADC_DIV, "adc_div", 0x0, LPC32XX_CLK_PERIPH),
+	LPC32XX_CLK_DEFINE(ADC_RTC, "adc_rtc", 0x0, LPC32XX_CLK_RTC),
+	LPC32XX_CLK_DEFINE(TEST1, "test1", 0x0,
+		LPC32XX_CLK_PERIPH, LPC32XX_CLK_RTC, LPC32XX_CLK_OSC),
+	LPC32XX_CLK_DEFINE(TEST2, "test2", 0x0,
+		LPC32XX_CLK_HCLK, LPC32XX_CLK_PERIPH, LPC32XX_CLK_USB,
+		LPC32XX_CLK_OSC, LPC32XX_CLK_PLL397X),
+
+	/* USB controller clocks */
+	LPC32XX_CLK_DEFINE(USB_AHB, "usb_ahb", 0x0, LPC32XX_CLK_USB),
+	LPC32XX_CLK_DEFINE(USB_OTG, "usb_otg", 0x0, LPC32XX_CLK_USB_AHB),
+	LPC32XX_CLK_DEFINE(USB_I2C, "usb_i2c", 0x0, LPC32XX_CLK_USB_AHB),
+	LPC32XX_CLK_DEFINE(USB_DEV, "usb_dev", 0x0, LPC32XX_CLK_USB_OTG),
+	LPC32XX_CLK_DEFINE(USB_HOST, "usb_host", 0x0, LPC32XX_CLK_USB_OTG),
+};
+
+struct lpc32xx_clk {
+	struct clk_hw hw;
+	u32 reg;
+	u32 enable;
+	u32 enable_mask;
+	u32 disable;
+	u32 disable_mask;
+	u32 busy;
+	u32 busy_mask;
+};
+
+enum clk_pll_mode {
+	PLL_UNKNOWN,
+	PLL_DIRECT,
+	PLL_BYPASS,
+	PLL_DIRECT_BYPASS,
+	PLL_INTEGER,
+	PLL_NON_INTEGER,
+};
+
+struct lpc32xx_pll_clk {
+	struct clk_hw hw;
+	u32 reg;
+	u32 enable;
+	unsigned long m_div;
+	unsigned long n_div;
+	unsigned long p_div;
+	enum clk_pll_mode mode;
+};
+
+struct lpc32xx_usb_clk {
+	struct clk_hw hw;
+	u32 ctrl_enable;
+	u32 ctrl_disable;
+	u32 ctrl_mask;
+	u32 enable;
+	u32 busy;
+};
+
+struct lpc32xx_clk_mux {
+	struct clk_hw	hw;
+	u32		reg;
+	u32		mask;
+	u8		shift;
+	u32		*table;
+	u8		flags;
+};
+
+struct lpc32xx_clk_div {
+	struct clk_hw	hw;
+	u32		reg;
+	u8		shift;
+	u8		width;
+	const struct clk_div_table	*table;
+	u8		flags;
+};
+
+struct lpc32xx_clk_gate {
+	struct clk_hw	hw;
+	u32		reg;
+	u8		bit_idx;
+	u8		flags;
+};
+
+#define to_lpc32xx_clk(_hw)	container_of(_hw, struct lpc32xx_clk, hw)
+#define to_lpc32xx_pll_clk(_hw)	container_of(_hw, struct lpc32xx_pll_clk, hw)
+#define to_lpc32xx_usb_clk(_hw)	container_of(_hw, struct lpc32xx_usb_clk, hw)
+#define to_lpc32xx_mux(_hw)	container_of(_hw, struct lpc32xx_clk_mux, hw)
+#define to_lpc32xx_div(_hw)	container_of(_hw, struct lpc32xx_clk_div, hw)
+#define to_lpc32xx_gate(_hw)	container_of(_hw, struct lpc32xx_clk_gate, hw)
+
+static inline bool pll_is_valid(u64 val0, u64 val1, u64 min, u64 max)
+{
+	return (val0 >= (val1 * min) && val0 <= (val1 * max));
+}
+
+static inline u32 lpc32xx_usb_clk_read(struct lpc32xx_usb_clk *clk)
+{
+	return readl(usb_clk_vbase + LPC32XX_USB_CLK_STS);
+}
+
+static inline void lpc32xx_usb_clk_write(struct lpc32xx_usb_clk *clk, u32 val)
+{
+	writel(val, usb_clk_vbase + LPC32XX_USB_CLK_CTRL);
+}
+
+static int clk_mask_enable(struct clk_hw *hw)
+{
+	struct lpc32xx_clk *clk = to_lpc32xx_clk(hw);
+	u32 val;
+
+	regmap_read(clk_regmap, clk->reg, &val);
+
+	if (clk->busy_mask && (val & clk->busy_mask) == clk->busy)
+		return -EBUSY;
+
+	return regmap_update_bits(clk_regmap, clk->reg,
+				  clk->enable_mask, clk->enable);
+}
+
+static void clk_mask_disable(struct clk_hw *hw)
+{
+	struct lpc32xx_clk *clk = to_lpc32xx_clk(hw);
+
+	regmap_update_bits(clk_regmap, clk->reg,
+			   clk->disable_mask, clk->disable);
+}
+
+static int clk_mask_is_enabled(struct clk_hw *hw)
+{
+	struct lpc32xx_clk *clk = to_lpc32xx_clk(hw);
+	u32 val;
+
+	regmap_read(clk_regmap, clk->reg, &val);
+
+	return ((val & clk->enable_mask) == clk->enable);
+}
+
+static const struct clk_ops clk_mask_ops = {
+	.enable = clk_mask_enable,
+	.disable = clk_mask_disable,
+	.is_enabled = clk_mask_is_enabled,
+};
+
+static int clk_pll_enable(struct clk_hw *hw)
+{
+	struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw);
+	u32 val, count;
+
+	regmap_update_bits(clk_regmap, clk->reg, clk->enable, clk->enable);
+
+	for (count = 0; count < 1000; count++) {
+		regmap_read(clk_regmap, clk->reg, &val);
+		if (val & PLL_CTRL_LOCK)
+			break;
+	}
+
+	if (val & PLL_CTRL_LOCK)
+		return 0;
+
+	return -ETIMEDOUT;
+}
+
+static void clk_pll_disable(struct clk_hw *hw)
+{
+	struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw);
+
+	regmap_update_bits(clk_regmap, clk->reg, clk->enable, 0x0);
+}
+
+static int clk_pll_is_enabled(struct clk_hw *hw)
+{
+	struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw);
+	u32 val;
+
+	regmap_read(clk_regmap, clk->reg, &val);
+
+	val &= clk->enable | PLL_CTRL_LOCK;
+	if (val == (clk->enable | PLL_CTRL_LOCK))
+		return 1;
+
+	return 0;
+}
+
+static unsigned long clk_pll_397x_recalc_rate(struct clk_hw *hw,
+					      unsigned long parent_rate)
+{
+	return parent_rate * 397;
+}
+
+static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
+					 unsigned long parent_rate)
+{
+	struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw);
+	bool is_direct, is_bypass, is_feedback;
+	unsigned long rate, cco_rate, ref_rate;
+	u32 val;
+
+	regmap_read(clk_regmap, clk->reg, &val);
+	is_direct = val & PLL_CTRL_DIRECT;
+	is_bypass = val & PLL_CTRL_BYPASS;
+	is_feedback = val & PLL_CTRL_FEEDBACK;
+
+	clk->m_div = ((val & PLL_CTRL_FEEDDIV) >> 1) + 1;
+	clk->n_div = ((val & PLL_CTRL_PREDIV) >> 9) + 1;
+	clk->p_div = ((val & PLL_CTRL_POSTDIV) >> 11) + 1;
+
+	if (is_direct && is_bypass) {
+		clk->p_div = 0;
+		clk->mode = PLL_DIRECT_BYPASS;
+		return parent_rate;
+	}
+	if (is_bypass) {
+		clk->mode = PLL_BYPASS;
+		return parent_rate / (1 << clk->p_div);
+	}
+	if (is_direct) {
+		clk->p_div = 0;
+		clk->mode = PLL_DIRECT;
+	}
+
+	ref_rate = parent_rate / clk->n_div;
+	rate = cco_rate = ref_rate * clk->m_div;
+
+	if (!is_direct) {
+		if (is_feedback) {
+			cco_rate *= (1 << clk->p_div);
+			clk->mode = PLL_INTEGER;
+		} else {
+			rate /= (1 << clk->p_div);
+			clk->mode = PLL_NON_INTEGER;
+		}
+	}
+
+	pr_debug("%s: %lu: 0x%x: %d/%d/%d, %lu/%lu/%d => %lu\n",
+		 clk_hw_get_name(hw),
+		 parent_rate, val, is_direct, is_bypass, is_feedback,
+		 clk->n_div, clk->m_div, (1 << clk->p_div), rate);
+
+	if (clk_pll_is_enabled(hw) &&
+	    !(pll_is_valid(parent_rate, 1, 1000000, 20000000)
+	      && pll_is_valid(cco_rate, 1, 156000000, 320000000)
+	      && pll_is_valid(ref_rate, 1, 1000000, 27000000)))
+		pr_err("%s: PLL clocks are not in valid ranges: %lu/%lu/%lu",
+		       clk_hw_get_name(hw),
+		       parent_rate, cco_rate, ref_rate);
+
+	return rate;
+}
+
+static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw);
+	u32 val;
+	unsigned long new_rate;
+
+	/* Validate PLL clock parameters computed on round rate stage */
+	switch (clk->mode) {
+	case PLL_DIRECT:
+		val = PLL_CTRL_DIRECT;
+		val |= (clk->m_div - 1) << 1;
+		val |= (clk->n_div - 1) << 9;
+		new_rate = (parent_rate * clk->m_div) / clk->n_div;
+		break;
+	case PLL_BYPASS:
+		val = PLL_CTRL_BYPASS;
+		val |= (clk->p_div - 1) << 11;
+		new_rate = parent_rate / (1 << (clk->p_div));
+		break;
+	case PLL_DIRECT_BYPASS:
+		val = PLL_CTRL_DIRECT | PLL_CTRL_BYPASS;
+		new_rate = parent_rate;
+		break;
+	case PLL_INTEGER:
+		val = PLL_CTRL_FEEDBACK;
+		val |= (clk->m_div - 1) << 1;
+		val |= (clk->n_div - 1) << 9;
+		val |= (clk->p_div - 1) << 11;
+		new_rate = (parent_rate * clk->m_div) / clk->n_div;
+		break;
+	case PLL_NON_INTEGER:
+		val = 0x0;
+		val |= (clk->m_div - 1) << 1;
+		val |= (clk->n_div - 1) << 9;
+		val |= (clk->p_div - 1) << 11;
+		new_rate = (parent_rate * clk->m_div) /
+				(clk->n_div * (1 << clk->p_div));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Sanity check that round rate is equal to the requested one */
+	if (new_rate != rate)
+		return -EINVAL;
+
+	return regmap_update_bits(clk_regmap, clk->reg, 0x1FFFF, val);
+}
+
+static long clk_hclk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+				    unsigned long *parent_rate)
+{
+	struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw);
+	u64 m_i, m, n, p, o = rate, i = *parent_rate, d = (u64)rate << 6;
+	int p_i, n_i;
+
+	pr_debug("%s: %lu/%lu\n", clk_hw_get_name(hw), *parent_rate, rate);
+
+	if (rate > 266500000)
+		return -EINVAL;
+
+	/* Have to check all 20 possibilities to find the minimal M */
+	for (p_i = 4; p_i >= 0; p_i--) {
+		for (n_i = 4; n_i > 0; n_i--) {
+			m_i = div64_u64(o * n_i * (1 << p_i), i);
+
+			/* Check for valid PLL parameter constraints */
+			if (!(m_i && m_i <= 256
+			      && pll_is_valid(i, n_i, 1000000, 27000000)
+			      && pll_is_valid(i * m_i * (1 << p_i), n_i,
+					      156000000, 320000000)))
+				continue;
+
+			/* Store some intermediate valid parameters */
+			if (o * n_i * (1 << p_i) - i * m_i <= d) {
+				m = m_i;
+				n = n_i;
+				p = p_i;
+				d = o * n_i * (1 << p_i) - i * m_i;
+			}
+		}
+	}
+
+	if (d == (u64)rate << 6) {
+		pr_err("%s: %lu: no valid PLL parameters are found\n",
+		       clk_hw_get_name(hw), rate);
+		return -EINVAL;
+	}
+
+	clk->m_div = m;
+	clk->n_div = n;
+	clk->p_div = p;
+
+	/* Set only direct or non-integer mode of PLL */
+	if (!p)
+		clk->mode = PLL_DIRECT;
+	else
+		clk->mode = PLL_NON_INTEGER;
+
+	o = div64_u64(i * m, n * (1 << p));
+
+	if (!d)
+		pr_debug("%s: %lu: found exact match: %llu/%llu/%llu\n",
+			 clk_hw_get_name(hw), rate, m, n, p);
+	else
+		pr_debug("%s: %lu: found closest: %llu/%llu/%llu - %llu\n",
+			 clk_hw_get_name(hw), rate, m, n, p, o);
+
+	return o;
+}
+
+static long clk_usb_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+				   unsigned long *parent_rate)
+{
+	struct lpc32xx_pll_clk *clk = to_lpc32xx_pll_clk(hw);
+	struct clk_hw *usb_div_hw, *osc_hw;
+	u64 d_i, n_i, m, o;
+
+	pr_debug("%s: %lu/%lu\n", clk_hw_get_name(hw), *parent_rate, rate);
+
+	/*
+	 * The only supported USB clock is 48MHz, with PLL internal constraints
+	 * on Fclkin, Fcco and Fref this implies that Fcco must be 192MHz
+	 * and post-divider must be 4, this slightly simplifies calculation of
+	 * USB divider, USB PLL N and M parameters.
+	 */
+	if (rate != 48000000)
+		return -EINVAL;
+
+	/* USB divider clock */
+	usb_div_hw = clk_hw_get_parent_by_index(hw, 0);
+	if (!usb_div_hw)
+		return -EINVAL;
+
+	/* Main oscillator clock */
+	osc_hw = clk_hw_get_parent_by_index(usb_div_hw, 0);
+	if (!osc_hw)
+		return -EINVAL;
+	o = clk_hw_get_rate(osc_hw);	/* must be in range 1..20 MHz */
+
+	/* Check if valid USB divider and USB PLL parameters exists */
+	for (d_i = 16; d_i >= 1; d_i--) {
+		for (n_i = 1; n_i <= 4; n_i++) {
+			m = div64_u64(192000000 * d_i * n_i, o);
+			if (!(m && m <= 256
+			      && m * o == 192000000 * d_i * n_i
+			      && pll_is_valid(o, d_i, 1000000, 20000000)
+			      && pll_is_valid(o, d_i * n_i, 1000000, 27000000)))
+				continue;
+
+			clk->n_div = n_i;
+			clk->m_div = m;
+			clk->p_div = 2;
+			clk->mode = PLL_NON_INTEGER;
+			*parent_rate = div64_u64(o, d_i);
+
+			return rate;
+		}
+	}
+
+	return -EINVAL;
+}
+
+#define LPC32XX_DEFINE_PLL_OPS(_name, _rc, _sr, _rr)			\
+	static const struct clk_ops clk_ ##_name ## _ops = {		\
+		.enable = clk_pll_enable,				\
+		.disable = clk_pll_disable,				\
+		.is_enabled = clk_pll_is_enabled,			\
+		.recalc_rate = _rc,					\
+		.set_rate = _sr,					\
+		.round_rate = _rr,					\
+	}
+
+LPC32XX_DEFINE_PLL_OPS(pll_397x, clk_pll_397x_recalc_rate, NULL, NULL);
+LPC32XX_DEFINE_PLL_OPS(hclk_pll, clk_pll_recalc_rate,
+		       clk_pll_set_rate, clk_hclk_pll_round_rate);
+LPC32XX_DEFINE_PLL_OPS(usb_pll,  clk_pll_recalc_rate,
+		       clk_pll_set_rate, clk_usb_pll_round_rate);
+
+static int clk_ddram_is_enabled(struct clk_hw *hw)
+{
+	struct lpc32xx_clk *clk = to_lpc32xx_clk(hw);
+	u32 val;
+
+	regmap_read(clk_regmap, clk->reg, &val);
+	val &= clk->enable_mask | clk->busy_mask;
+
+	return (val == (BIT(7) | BIT(0)) ||
+		val == (BIT(8) | BIT(1)));
+}
+
+static int clk_ddram_enable(struct clk_hw *hw)
+{
+	struct lpc32xx_clk *clk = to_lpc32xx_clk(hw);
+	u32 val, hclk_div;
+
+	regmap_read(clk_regmap, clk->reg, &val);
+	hclk_div = val & clk->busy_mask;
+
+	/*
+	 * DDRAM clock must be 2 times higher than HCLK,
+	 * this implies DDRAM clock can not be enabled,
+	 * if HCLK clock rate is equal to ARM clock rate
+	 */
+	if (hclk_div == 0x0 || hclk_div == (BIT(1) | BIT(0)))
+		return -EINVAL;
+
+	return regmap_update_bits(clk_regmap, clk->reg,
+				  clk->enable_mask, hclk_div << 7);
+}
+
+static unsigned long clk_ddram_recalc_rate(struct clk_hw *hw,
+					   unsigned long parent_rate)
+{
+	struct lpc32xx_clk *clk = to_lpc32xx_clk(hw);
+	u32 val;
+
+	if (!clk_ddram_is_enabled(hw))
+		return 0;
+
+	regmap_read(clk_regmap, clk->reg, &val);
+	val &= clk->enable_mask;
+
+	return parent_rate / (val >> 7);
+}
+
+static const struct clk_ops clk_ddram_ops = {
+	.enable = clk_ddram_enable,
+	.disable = clk_mask_disable,
+	.is_enabled = clk_ddram_is_enabled,
+	.recalc_rate = clk_ddram_recalc_rate,
+};
+
+static unsigned long lpc32xx_clk_uart_recalc_rate(struct clk_hw *hw,
+						  unsigned long parent_rate)
+{
+	struct lpc32xx_clk *clk = to_lpc32xx_clk(hw);
+	u32 val, x, y;
+
+	regmap_read(clk_regmap, clk->reg, &val);
+	x = (val & 0xFF00) >> 8;
+	y = val & 0xFF;
+
+	if (x && y)
+		return (parent_rate * x) / y;
+	else
+		return 0;
+}
+
+static const struct clk_ops lpc32xx_uart_div_ops = {
+	.recalc_rate = lpc32xx_clk_uart_recalc_rate,
+};
+
+static const struct clk_div_table clk_hclk_div_table[] = {
+	{ .val = 0, .div = 1 },
+	{ .val = 1, .div = 2 },
+	{ .val = 2, .div = 4 },
+	{ },
+};
+
+static u32 test1_mux_table[] = { 0, 1, 2, };
+static u32 test2_mux_table[] = { 0, 1, 2, 5, 7, };
+
+static int clk_usb_enable(struct clk_hw *hw)
+{
+	struct lpc32xx_usb_clk *clk = to_lpc32xx_usb_clk(hw);
+	u32 val, ctrl_val, count;
+
+	pr_debug("%s: 0x%x\n", clk_hw_get_name(hw), clk->enable);
+
+	if (clk->ctrl_mask) {
+		regmap_read(clk_regmap, LPC32XX_CLKPWR_USB_CTRL, &ctrl_val);
+		regmap_update_bits(clk_regmap, LPC32XX_CLKPWR_USB_CTRL,
+				   clk->ctrl_mask, clk->ctrl_enable);
+	}
+
+	val = lpc32xx_usb_clk_read(clk);
+	if (clk->busy && (val & clk->busy) == clk->busy) {
+		if (clk->ctrl_mask)
+			regmap_write(clk_regmap, LPC32XX_CLKPWR_USB_CTRL,
+				     ctrl_val);
+		return -EBUSY;
+	}
+
+	val |= clk->enable;
+	lpc32xx_usb_clk_write(clk, val);
+
+	for (count = 0; count < 1000; count++) {
+		val = lpc32xx_usb_clk_read(clk);
+		if ((val & clk->enable) == clk->enable)
+			break;
+	}
+
+	if ((val & clk->enable) == clk->enable)
+		return 0;
+
+	if (clk->ctrl_mask)
+		regmap_write(clk_regmap, LPC32XX_CLKPWR_USB_CTRL, ctrl_val);
+
+	return -ETIMEDOUT;
+}
+
+static void clk_usb_disable(struct clk_hw *hw)
+{
+	struct lpc32xx_usb_clk *clk = to_lpc32xx_usb_clk(hw);
+	u32 val = lpc32xx_usb_clk_read(clk);
+
+	val &= ~clk->enable;
+	lpc32xx_usb_clk_write(clk, val);
+
+	if (clk->ctrl_mask)
+		regmap_update_bits(clk_regmap, LPC32XX_CLKPWR_USB_CTRL,
+				   clk->ctrl_mask, clk->ctrl_disable);
+}
+
+static int clk_usb_is_enabled(struct clk_hw *hw)
+{
+	struct lpc32xx_usb_clk *clk = to_lpc32xx_usb_clk(hw);
+	u32 ctrl_val, val;
+
+	if (clk->ctrl_mask) {
+		regmap_read(clk_regmap, LPC32XX_CLKPWR_USB_CTRL, &ctrl_val);
+		if ((ctrl_val & clk->ctrl_mask) != clk->ctrl_enable)
+			return 0;
+	}
+
+	val = lpc32xx_usb_clk_read(clk);
+
+	return ((val & clk->enable) == clk->enable);
+}
+
+static unsigned long clk_usb_i2c_recalc_rate(struct clk_hw *hw,
+					     unsigned long parent_rate)
+{
+	return clk_get_rate(clk[LPC32XX_CLK_PERIPH]);
+}
+
+static const struct clk_ops clk_usb_ops = {
+	.enable = clk_usb_enable,
+	.disable = clk_usb_disable,
+	.is_enabled = clk_usb_is_enabled,
+};
+
+static const struct clk_ops clk_usb_i2c_ops = {
+	.enable = clk_usb_enable,
+	.disable = clk_usb_disable,
+	.is_enabled = clk_usb_is_enabled,
+	.recalc_rate = clk_usb_i2c_recalc_rate,
+};
+
+static int clk_gate_enable(struct clk_hw *hw)
+{
+	struct lpc32xx_clk_gate *clk = to_lpc32xx_gate(hw);
+	u32 mask = BIT(clk->bit_idx);
+	u32 val = (clk->flags & CLK_GATE_SET_TO_DISABLE ? 0x0 : mask);
+
+	return regmap_update_bits(clk_regmap, clk->reg, mask, val);
+}
+
+static void clk_gate_disable(struct clk_hw *hw)
+{
+	struct lpc32xx_clk_gate *clk = to_lpc32xx_gate(hw);
+	u32 mask = BIT(clk->bit_idx);
+	u32 val = (clk->flags & CLK_GATE_SET_TO_DISABLE ? mask : 0x0);
+
+	regmap_update_bits(clk_regmap, clk->reg, mask, val);
+}
+
+static int clk_gate_is_enabled(struct clk_hw *hw)
+{
+	struct lpc32xx_clk_gate *clk = to_lpc32xx_gate(hw);
+	u32 val;
+	bool is_set;
+
+	regmap_read(clk_regmap, clk->reg, &val);
+	is_set = val & BIT(clk->bit_idx);
+
+	return (clk->flags & CLK_GATE_SET_TO_DISABLE ? !is_set : is_set);
+}
+
+static const struct clk_ops lpc32xx_clk_gate_ops = {
+	.enable = clk_gate_enable,
+	.disable = clk_gate_disable,
+	.is_enabled = clk_gate_is_enabled,
+};
+
+#define div_mask(width)	((1 << (width)) - 1)
+
+static unsigned int _get_table_div(const struct clk_div_table *table,
+							unsigned int val)
+{
+	const struct clk_div_table *clkt;
+
+	for (clkt = table; clkt->div; clkt++)
+		if (clkt->val == val)
+			return clkt->div;
+	return 0;
+}
+
+static unsigned int _get_div(const struct clk_div_table *table,
+			     unsigned int val, unsigned long flags, u8 width)
+{
+	if (flags & CLK_DIVIDER_ONE_BASED)
+		return val;
+	if (table)
+		return _get_table_div(table, val);
+	return val + 1;
+}
+
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct lpc32xx_clk_div *divider = to_lpc32xx_div(hw);
+	unsigned int val;
+
+	regmap_read(clk_regmap, divider->reg, &val);
+
+	val >>= divider->shift;
+	val &= div_mask(divider->width);
+
+	return divider_recalc_rate(hw, parent_rate, val, divider->table,
+				   divider->flags);
+}
+
+static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct lpc32xx_clk_div *divider = to_lpc32xx_div(hw);
+	unsigned int bestdiv;
+
+	/* if read only, just return current value */
+	if (divider->flags & CLK_DIVIDER_READ_ONLY) {
+		regmap_read(clk_regmap, divider->reg, &bestdiv);
+		bestdiv >>= divider->shift;
+		bestdiv &= div_mask(divider->width);
+		bestdiv = _get_div(divider->table, bestdiv, divider->flags,
+			divider->width);
+		return DIV_ROUND_UP(*prate, bestdiv);
+	}
+
+	return divider_round_rate(hw, rate, prate, divider->table,
+				  divider->width, divider->flags);
+}
+
+static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long parent_rate)
+{
+	struct lpc32xx_clk_div *divider = to_lpc32xx_div(hw);
+	unsigned int value;
+
+	value = divider_get_val(rate, parent_rate, divider->table,
+				divider->width, divider->flags);
+
+	return regmap_update_bits(clk_regmap, divider->reg,
+				  div_mask(divider->width) << divider->shift,
+				  value << divider->shift);
+}
+
+static const struct clk_ops lpc32xx_clk_divider_ops = {
+	.recalc_rate = clk_divider_recalc_rate,
+	.round_rate = clk_divider_round_rate,
+	.set_rate = clk_divider_set_rate,
+};
+
+static u8 clk_mux_get_parent(struct clk_hw *hw)
+{
+	struct lpc32xx_clk_mux *mux = to_lpc32xx_mux(hw);
+	u32 num_parents = clk_hw_get_num_parents(hw);
+	u32 val;
+
+	regmap_read(clk_regmap, mux->reg, &val);
+	val >>= mux->shift;
+	val &= mux->mask;
+
+	if (mux->table) {
+		u32 i;
+
+		for (i = 0; i < num_parents; i++)
+			if (mux->table[i] == val)
+				return i;
+		return -EINVAL;
+	}
+
+	if (val >= num_parents)
+		return -EINVAL;
+
+	return val;
+}
+
+static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct lpc32xx_clk_mux *mux = to_lpc32xx_mux(hw);
+
+	if (mux->table)
+		index = mux->table[index];
+
+	return regmap_update_bits(clk_regmap, mux->reg,
+			  mux->mask << mux->shift, index << mux->shift);
+}
+
+static const struct clk_ops lpc32xx_clk_mux_ro_ops = {
+	.get_parent = clk_mux_get_parent,
+};
+
+static const struct clk_ops lpc32xx_clk_mux_ops = {
+	.get_parent = clk_mux_get_parent,
+	.set_parent = clk_mux_set_parent,
+	.determine_rate = __clk_mux_determine_rate,
+};
+
+enum lpc32xx_clk_type {
+	CLK_FIXED,
+	CLK_MUX,
+	CLK_DIV,
+	CLK_GATE,
+	CLK_COMPOSITE,
+	CLK_LPC32XX,
+	CLK_LPC32XX_PLL,
+	CLK_LPC32XX_USB,
+};
+
+struct clk_hw_proto0 {
+	const struct clk_ops *ops;
+	union {
+		struct lpc32xx_pll_clk pll;
+		struct lpc32xx_clk clk;
+		struct lpc32xx_usb_clk usb_clk;
+		struct lpc32xx_clk_mux mux;
+		struct lpc32xx_clk_div div;
+		struct lpc32xx_clk_gate gate;
+	};
+};
+
+struct clk_hw_proto1 {
+	struct clk_hw_proto0 *mux;
+	struct clk_hw_proto0 *div;
+	struct clk_hw_proto0 *gate;
+};
+
+struct clk_hw_proto {
+	enum lpc32xx_clk_type type;
+
+	union {
+		struct clk_fixed_rate f;
+		struct clk_hw_proto0 hw0;
+		struct clk_hw_proto1 hw1;
+	};
+};
+
+#define LPC32XX_DEFINE_FIXED(_idx, _rate, _flags)			\
+[CLK_PREFIX(_idx)] = {							\
+	.type = CLK_FIXED,						\
+	{								\
+		.f = {							\
+			.fixed_rate = (_rate),				\
+			.flags = (_flags),				\
+		},							\
+	},								\
+}
+
+#define LPC32XX_DEFINE_PLL(_idx, _name, _reg, _enable)			\
+[CLK_PREFIX(_idx)] = {							\
+	.type = CLK_LPC32XX_PLL,					\
+	{								\
+		.hw0 = {						\
+			.ops = &clk_ ##_name ## _ops,			\
+			{						\
+				.pll = {				\
+					.reg = LPC32XX_CLKPWR_ ## _reg,	\
+					.enable = (_enable),		\
+				},					\
+			},						\
+		},							\
+	},								\
+}
+
+#define LPC32XX_DEFINE_MUX(_idx, _reg, _shift, _mask, _table, _flags)	\
+[CLK_PREFIX(_idx)] = {							\
+	.type = CLK_MUX,						\
+	{								\
+		.hw0 = {						\
+			.ops = (_flags & CLK_MUX_READ_ONLY ?		\
+				&lpc32xx_clk_mux_ro_ops :		\
+				&lpc32xx_clk_mux_ops),			\
+			{						\
+				.mux = {				\
+					.reg = LPC32XX_CLKPWR_ ## _reg,	\
+					.mask = (_mask),		\
+					.shift = (_shift),		\
+					.table = (_table),		\
+					.flags = (_flags),		\
+				},					\
+			},						\
+		},							\
+	},								\
+}
+
+#define LPC32XX_DEFINE_DIV(_idx, _reg, _shift, _width, _table, _flags)	\
+[CLK_PREFIX(_idx)] = {							\
+	.type = CLK_DIV,						\
+	{								\
+		.hw0 = {						\
+			.ops = &lpc32xx_clk_divider_ops,		\
+			{						\
+				.div = {				\
+					.reg = LPC32XX_CLKPWR_ ## _reg,	\
+					.shift = (_shift),		\
+					.width = (_width),		\
+					.table = (_table),		\
+					.flags = (_flags),		\
+				 },					\
+			},						\
+		 },							\
+	},								\
+}
+
+#define LPC32XX_DEFINE_GATE(_idx, _reg, _bit, _flags)			\
+[CLK_PREFIX(_idx)] = {							\
+	.type = CLK_GATE,						\
+	{								\
+		.hw0 = {						\
+			.ops = &lpc32xx_clk_gate_ops,			\
+			{						\
+				.gate = {				\
+					.reg = LPC32XX_CLKPWR_ ## _reg,	\
+					.bit_idx = (_bit),		\
+					.flags = (_flags),		\
+				},					\
+			},						\
+		},							\
+	},								\
+}
+
+#define LPC32XX_DEFINE_CLK(_idx, _reg, _e, _em, _d, _dm, _b, _bm, _ops)	\
+[CLK_PREFIX(_idx)] = {							\
+	.type = CLK_LPC32XX,						\
+	{								\
+		.hw0 = {						\
+			.ops = &(_ops),					\
+			{						\
+				.clk = {				\
+					.reg = LPC32XX_CLKPWR_ ## _reg,	\
+					.enable = (_e),			\
+					.enable_mask = (_em),		\
+					.disable = (_d),		\
+					.disable_mask = (_dm),		\
+					.busy = (_b),			\
+					.busy_mask = (_bm),		\
+				},					\
+			},						\
+		},							\
+	},								\
+}
+
+#define LPC32XX_DEFINE_USB(_idx, _ce, _cd, _cm, _e, _b, _ops)		\
+[CLK_PREFIX(_idx)] = {							\
+	.type = CLK_LPC32XX_USB,					\
+	{								\
+		.hw0 = {						\
+			.ops = &(_ops),					\
+			{						\
+				.usb_clk = {				\
+					.ctrl_enable = (_ce),		\
+					.ctrl_disable = (_cd),		\
+					.ctrl_mask = (_cm),		\
+					.enable = (_e),			\
+					.busy = (_b),			\
+				}					\
+			},						\
+		}							\
+	},								\
+}
+
+#define LPC32XX_DEFINE_COMPOSITE(_idx, _mux, _div, _gate)		\
+[CLK_PREFIX(_idx)] = {							\
+	.type = CLK_COMPOSITE,						\
+	{								\
+		.hw1 = {						\
+		.mux = (CLK_PREFIX(_mux) == LPC32XX_CLK__NULL ? NULL :	\
+			&clk_hw_proto[CLK_PREFIX(_mux)].hw0),		\
+		.div = (CLK_PREFIX(_div) == LPC32XX_CLK__NULL ? NULL :	\
+			&clk_hw_proto[CLK_PREFIX(_div)].hw0),		\
+		.gate = (CLK_PREFIX(_gate) == LPC32XX_CLK__NULL ? NULL :\
+			 &clk_hw_proto[CLK_PREFIX(_gate)].hw0),		\
+		},							\
+	},								\
+}
+
+static struct clk_hw_proto clk_hw_proto[LPC32XX_CLK_HW_MAX] = {
+	LPC32XX_DEFINE_FIXED(RTC, 32768, 0),
+	LPC32XX_DEFINE_PLL(PLL397X, pll_397x, HCLKPLL_CTRL, BIT(1)),
+	LPC32XX_DEFINE_PLL(HCLK_PLL, hclk_pll, HCLKPLL_CTRL, PLL_CTRL_ENABLE),
+	LPC32XX_DEFINE_PLL(USB_PLL, usb_pll, USB_CTRL, PLL_CTRL_ENABLE),
+	LPC32XX_DEFINE_GATE(OSC, OSC_CTRL, 0, CLK_GATE_SET_TO_DISABLE),
+	LPC32XX_DEFINE_GATE(USB, USB_CTRL, 18, 0),
+
+	LPC32XX_DEFINE_DIV(HCLK_DIV_PERIPH, HCLKDIV_CTRL, 2, 5, NULL,
+			   CLK_DIVIDER_READ_ONLY),
+	LPC32XX_DEFINE_DIV(HCLK_DIV, HCLKDIV_CTRL, 0, 2, clk_hclk_div_table,
+			   CLK_DIVIDER_READ_ONLY),
+
+	/* Register 3 read-only muxes with a single control PWR_CTRL[2] */
+	LPC32XX_DEFINE_MUX(SYSCLK_PERIPH_MUX, PWR_CTRL, 2, 0x1, NULL,
+			   CLK_MUX_READ_ONLY),
+	LPC32XX_DEFINE_MUX(SYSCLK_HCLK_MUX, PWR_CTRL, 2, 0x1, NULL,
+			   CLK_MUX_READ_ONLY),
+	LPC32XX_DEFINE_MUX(SYSCLK_ARM_MUX, PWR_CTRL, 2, 0x1, NULL,
+			   CLK_MUX_READ_ONLY),
+	/* Register 2 read-only muxes with a single control PWR_CTRL[10] */
+	LPC32XX_DEFINE_MUX(PERIPH_HCLK_MUX, PWR_CTRL, 10, 0x1, NULL,
+			   CLK_MUX_READ_ONLY),
+	LPC32XX_DEFINE_MUX(PERIPH_ARM_MUX, PWR_CTRL, 10, 0x1, NULL,
+			   CLK_MUX_READ_ONLY),
+
+	/* 3 always on gates with a single control PWR_CTRL[0] same as OSC */
+	LPC32XX_DEFINE_GATE(PERIPH, PWR_CTRL, 0, CLK_GATE_SET_TO_DISABLE),
+	LPC32XX_DEFINE_GATE(HCLK, PWR_CTRL, 0, CLK_GATE_SET_TO_DISABLE),
+	LPC32XX_DEFINE_GATE(ARM, PWR_CTRL, 0, CLK_GATE_SET_TO_DISABLE),
+
+	LPC32XX_DEFINE_GATE(ARM_VFP, DEBUG_CTRL, 4, 0),
+	LPC32XX_DEFINE_GATE(DMA, DMA_CLK_CTRL, 0, 0),
+	LPC32XX_DEFINE_CLK(DDRAM, HCLKDIV_CTRL, 0x0, BIT(8) | BIT(7),
+		   0x0, BIT(8) | BIT(7), 0x0, BIT(1) | BIT(0), clk_ddram_ops),
+
+	LPC32XX_DEFINE_GATE(TIMER0, TIMCLK_CTRL1, 2, 0),
+	LPC32XX_DEFINE_GATE(TIMER1, TIMCLK_CTRL1, 3, 0),
+	LPC32XX_DEFINE_GATE(TIMER2, TIMCLK_CTRL1, 4, 0),
+	LPC32XX_DEFINE_GATE(TIMER3, TIMCLK_CTRL1, 5, 0),
+	LPC32XX_DEFINE_GATE(TIMER4, TIMCLK_CTRL1, 0, 0),
+	LPC32XX_DEFINE_GATE(TIMER5, TIMCLK_CTRL1, 1, 0),
+
+	LPC32XX_DEFINE_GATE(SSP0, SSP_CTRL, 0, 0),
+	LPC32XX_DEFINE_GATE(SSP1, SSP_CTRL, 1, 0),
+	LPC32XX_DEFINE_GATE(SPI1, SPI_CTRL, 0, 0),
+	LPC32XX_DEFINE_GATE(SPI2, SPI_CTRL, 4, 0),
+	LPC32XX_DEFINE_GATE(I2S0, I2S_CTRL, 0, 0),
+	LPC32XX_DEFINE_GATE(I2S1, I2S_CTRL, 1, 0),
+	LPC32XX_DEFINE_GATE(I2C1, I2CCLK_CTRL, 0, 0),
+	LPC32XX_DEFINE_GATE(I2C2, I2CCLK_CTRL, 1, 0),
+	LPC32XX_DEFINE_GATE(WDOG, TIMCLK_CTRL, 0, 0),
+	LPC32XX_DEFINE_GATE(HSTIMER, TIMCLK_CTRL, 1, 0),
+
+	LPC32XX_DEFINE_GATE(KEY, KEYCLK_CTRL, 0, 0),
+	LPC32XX_DEFINE_GATE(MCPWM, TIMCLK_CTRL1, 6, 0),
+
+	LPC32XX_DEFINE_MUX(PWM1_MUX, PWMCLK_CTRL, 1, 0x1, NULL, 0),
+	LPC32XX_DEFINE_DIV(PWM1_DIV, PWMCLK_CTRL, 4, 4, NULL,
+			   CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO),
+	LPC32XX_DEFINE_GATE(PWM1_GATE, PWMCLK_CTRL, 0, 0),
+	LPC32XX_DEFINE_COMPOSITE(PWM1, PWM1_MUX, PWM1_DIV, PWM1_GATE),
+
+	LPC32XX_DEFINE_MUX(PWM2_MUX, PWMCLK_CTRL, 3, 0x1, NULL, 0),
+	LPC32XX_DEFINE_DIV(PWM2_DIV, PWMCLK_CTRL, 8, 4, NULL,
+			   CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO),
+	LPC32XX_DEFINE_GATE(PWM2_GATE, PWMCLK_CTRL, 2, 0),
+	LPC32XX_DEFINE_COMPOSITE(PWM2, PWM2_MUX, PWM2_DIV, PWM2_GATE),
+
+	LPC32XX_DEFINE_MUX(UART3_MUX, UART3_CLK_CTRL, 16, 0x1, NULL, 0),
+	LPC32XX_DEFINE_CLK(UART3_DIV, UART3_CLK_CTRL,
+			   0, 0, 0, 0, 0, 0, lpc32xx_uart_div_ops),
+	LPC32XX_DEFINE_GATE(UART3_GATE, UART_CLK_CTRL, 0, 0),
+	LPC32XX_DEFINE_COMPOSITE(UART3, UART3_MUX, UART3_DIV, UART3_GATE),
+
+	LPC32XX_DEFINE_MUX(UART4_MUX, UART4_CLK_CTRL, 16, 0x1, NULL, 0),
+	LPC32XX_DEFINE_CLK(UART4_DIV, UART4_CLK_CTRL,
+			   0, 0, 0, 0, 0, 0, lpc32xx_uart_div_ops),
+	LPC32XX_DEFINE_GATE(UART4_GATE, UART_CLK_CTRL, 1, 0),
+	LPC32XX_DEFINE_COMPOSITE(UART4, UART4_MUX, UART4_DIV, UART4_GATE),
+
+	LPC32XX_DEFINE_MUX(UART5_MUX, UART5_CLK_CTRL, 16, 0x1, NULL, 0),
+	LPC32XX_DEFINE_CLK(UART5_DIV, UART5_CLK_CTRL,
+			   0, 0, 0, 0, 0, 0, lpc32xx_uart_div_ops),
+	LPC32XX_DEFINE_GATE(UART5_GATE, UART_CLK_CTRL, 2, 0),
+	LPC32XX_DEFINE_COMPOSITE(UART5, UART5_MUX, UART5_DIV, UART5_GATE),
+
+	LPC32XX_DEFINE_MUX(UART6_MUX, UART6_CLK_CTRL, 16, 0x1, NULL, 0),
+	LPC32XX_DEFINE_CLK(UART6_DIV, UART6_CLK_CTRL,
+			   0, 0, 0, 0, 0, 0, lpc32xx_uart_div_ops),
+	LPC32XX_DEFINE_GATE(UART6_GATE, UART_CLK_CTRL, 3, 0),
+	LPC32XX_DEFINE_COMPOSITE(UART6, UART6_MUX, UART6_DIV, UART6_GATE),
+
+	LPC32XX_DEFINE_CLK(IRDA, IRDA_CLK_CTRL,
+			   0, 0, 0, 0, 0, 0, lpc32xx_uart_div_ops),
+
+	LPC32XX_DEFINE_MUX(TEST1_MUX, TEST_CLK_CTRL, 5, 0x3,
+			   test1_mux_table, 0),
+	LPC32XX_DEFINE_GATE(TEST1_GATE, TEST_CLK_CTRL, 4, 0),
+	LPC32XX_DEFINE_COMPOSITE(TEST1, TEST1_MUX, _NULL, TEST1_GATE),
+
+	LPC32XX_DEFINE_MUX(TEST2_MUX, TEST_CLK_CTRL, 1, 0x7,
+			   test2_mux_table, 0),
+	LPC32XX_DEFINE_GATE(TEST2_GATE, TEST_CLK_CTRL, 0, 0),
+	LPC32XX_DEFINE_COMPOSITE(TEST2, TEST2_MUX, _NULL, TEST2_GATE),
+
+	LPC32XX_DEFINE_MUX(SYS, SYSCLK_CTRL, 0, 0x1, NULL, CLK_MUX_READ_ONLY),
+
+	LPC32XX_DEFINE_DIV(USB_DIV_DIV, USB_DIV, 0, 4, NULL, 0),
+	LPC32XX_DEFINE_GATE(USB_DIV_GATE, USB_CTRL, 17, 0),
+	LPC32XX_DEFINE_COMPOSITE(USB_DIV, _NULL, USB_DIV_DIV, USB_DIV_GATE),
+
+	LPC32XX_DEFINE_DIV(SD_DIV, MS_CTRL, 0, 4, NULL,
+			   CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO),
+	LPC32XX_DEFINE_CLK(SD_GATE, MS_CTRL, BIT(5) | BIT(9), BIT(5) | BIT(9),
+			   0x0, BIT(5) | BIT(9), 0x0, 0x0, clk_mask_ops),
+	LPC32XX_DEFINE_COMPOSITE(SD, _NULL, SD_DIV, SD_GATE),
+
+	LPC32XX_DEFINE_DIV(LCD_DIV, LCDCLK_CTRL, 0, 5, NULL, 0),
+	LPC32XX_DEFINE_GATE(LCD_GATE, LCDCLK_CTRL, 5, 0),
+	LPC32XX_DEFINE_COMPOSITE(LCD, _NULL, LCD_DIV, LCD_GATE),
+
+	LPC32XX_DEFINE_CLK(MAC, MACCLK_CTRL,
+			   BIT(2) | BIT(1) | BIT(0), BIT(2) | BIT(1) | BIT(0),
+			   BIT(2) | BIT(1) | BIT(0), BIT(2) | BIT(1) | BIT(0),
+			   0x0, 0x0, clk_mask_ops),
+	LPC32XX_DEFINE_CLK(SLC, FLASHCLK_CTRL,
+			   BIT(2) | BIT(0), BIT(2) | BIT(0), 0x0,
+			   BIT(0), BIT(1), BIT(2) | BIT(1), clk_mask_ops),
+	LPC32XX_DEFINE_CLK(MLC, FLASHCLK_CTRL,
+			   BIT(1), BIT(2) | BIT(1), 0x0, BIT(1),
+			   BIT(2) | BIT(0), BIT(2) | BIT(0), clk_mask_ops),
+	/*
+	 * ADC/TS clock unfortunately cannot be registered as a composite one
+	 * due to a different connection of gate, div and mux, e.g. gating it
+	 * won't mean that the clock is off, if peripheral clock is its parent:
+	 *
+	 * rtc-->[gate]-->|     |
+	 *                | mux |--> adc/ts
+	 * pclk-->[div]-->|     |
+	 *
+	 * Constraints:
+	 * ADC --- resulting clock must be <= 4.5 MHz
+	 * TS  --- resulting clock must be <= 400 KHz
+	 */
+	LPC32XX_DEFINE_DIV(ADC_DIV, ADCCLK_CTRL1, 0, 8, NULL, 0),
+	LPC32XX_DEFINE_GATE(ADC_RTC, ADCCLK_CTRL, 0, 0),
+	LPC32XX_DEFINE_MUX(ADC, ADCCLK_CTRL1, 8, 0x1, NULL, 0),
+
+	/* USB controller clocks */
+	LPC32XX_DEFINE_USB(USB_AHB,
+			   BIT(24), 0x0, BIT(24), BIT(4), 0, clk_usb_ops),
+	LPC32XX_DEFINE_USB(USB_OTG,
+			   0x0, 0x0, 0x0, BIT(3), 0, clk_usb_ops),
+	LPC32XX_DEFINE_USB(USB_I2C,
+			   0x0, BIT(23), BIT(23), BIT(2), 0, clk_usb_i2c_ops),
+	LPC32XX_DEFINE_USB(USB_DEV,
+			   BIT(22), 0x0, BIT(22), BIT(1), BIT(0), clk_usb_ops),
+	LPC32XX_DEFINE_USB(USB_HOST,
+			   BIT(21), 0x0, BIT(21), BIT(0), BIT(1), clk_usb_ops),
+};
+
+static struct clk * __init lpc32xx_clk_register(u32 id)
+{
+	const struct clk_proto_t *lpc32xx_clk = &clk_proto[id];
+	struct clk_hw_proto *clk_hw = &clk_hw_proto[id];
+	const char *parents[LPC32XX_CLK_PARENTS_MAX];
+	struct clk *clk;
+	unsigned int i;
+
+	for (i = 0; i < lpc32xx_clk->num_parents; i++)
+		parents[i] = clk_proto[lpc32xx_clk->parents[i]].name;
+
+	pr_debug("%s: derived from '%s', clock type %d\n", lpc32xx_clk->name,
+		 parents[0], clk_hw->type);
+
+	switch (clk_hw->type) {
+	case CLK_LPC32XX:
+	case CLK_LPC32XX_PLL:
+	case CLK_LPC32XX_USB:
+	case CLK_MUX:
+	case CLK_DIV:
+	case CLK_GATE:
+	{
+		struct clk_init_data clk_init = {
+			.name = lpc32xx_clk->name,
+			.parent_names = parents,
+			.num_parents = lpc32xx_clk->num_parents,
+			.flags = lpc32xx_clk->flags,
+			.ops = clk_hw->hw0.ops,
+		};
+		struct clk_hw *hw;
+
+		if (clk_hw->type == CLK_LPC32XX)
+			hw = &clk_hw->hw0.clk.hw;
+		else if (clk_hw->type == CLK_LPC32XX_PLL)
+			hw = &clk_hw->hw0.pll.hw;
+		else if (clk_hw->type == CLK_LPC32XX_USB)
+			hw = &clk_hw->hw0.usb_clk.hw;
+		else if (clk_hw->type == CLK_MUX)
+			hw = &clk_hw->hw0.mux.hw;
+		else if (clk_hw->type == CLK_DIV)
+			hw = &clk_hw->hw0.div.hw;
+		else if (clk_hw->type == CLK_GATE)
+			hw = &clk_hw->hw0.gate.hw;
+
+		hw->init = &clk_init;
+		clk = clk_register(NULL, hw);
+		break;
+	}
+	case CLK_COMPOSITE:
+	{
+		struct clk_hw *mux_hw = NULL, *div_hw = NULL, *gate_hw = NULL;
+		const struct clk_ops *mops = NULL, *dops = NULL, *gops = NULL;
+		struct clk_hw_proto0 *mux0, *div0, *gate0;
+
+		mux0 = clk_hw->hw1.mux;
+		div0 = clk_hw->hw1.div;
+		gate0 = clk_hw->hw1.gate;
+		if (mux0) {
+			mops = mux0->ops;
+			mux_hw = &mux0->clk.hw;
+		}
+		if (div0) {
+			dops = div0->ops;
+			div_hw = &div0->clk.hw;
+		}
+		if (gate0) {
+			gops = gate0->ops;
+			gate_hw = &gate0->clk.hw;
+		}
+
+		clk = clk_register_composite(NULL, lpc32xx_clk->name,
+				parents, lpc32xx_clk->num_parents,
+				mux_hw, mops, div_hw, dops,
+				gate_hw, gops, lpc32xx_clk->flags);
+		break;
+	}
+	case CLK_FIXED:
+	{
+		struct clk_fixed_rate *fixed = &clk_hw->f;
+
+		clk = clk_register_fixed_rate(NULL, lpc32xx_clk->name,
+			parents[0], fixed->flags, fixed->fixed_rate);
+		break;
+	}
+	default:
+		clk = ERR_PTR(-EINVAL);
+	}
+
+	return clk;
+}
+
+static void __init lpc32xx_clk_init(struct device_node *np)
+{
+	unsigned int i;
+	struct clk *clk_osc, *clk_32k;
+	void __iomem *base = NULL;
+
+	/* Ensure that parent clocks are available and valid */
+	clk_32k = of_clk_get_by_name(np, clk_proto[LPC32XX_CLK_XTAL_32K].name);
+	if (IS_ERR(clk_32k)) {
+		pr_err("failed to find external 32KHz clock: %ld\n",
+		       PTR_ERR(clk_32k));
+		return;
+	}
+	if (clk_get_rate(clk_32k) != 32768) {
+		pr_err("invalid clock rate of external 32KHz oscillator");
+		return;
+	}
+
+	clk_osc = of_clk_get_by_name(np, clk_proto[LPC32XX_CLK_XTAL].name);
+	if (IS_ERR(clk_osc)) {
+		pr_err("failed to find external main oscillator clock: %ld\n",
+		       PTR_ERR(clk_osc));
+		return;
+	}
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("failed to map system control block registers\n");
+		return;
+	}
+
+	clk_regmap = regmap_init_mmio(NULL, base, &lpc32xx_scb_regmap_config);
+	if (IS_ERR(clk_regmap)) {
+		pr_err("failed to regmap system control block: %ld\n",
+			PTR_ERR(clk_regmap));
+		return;
+	}
+
+	for (i = 0; i < LPC32XX_CLK_MAX; i++) {
+		clk[i] = lpc32xx_clk_register(i);
+		if (IS_ERR(clk[i])) {
+			pr_err("failed to register %s clock: %ld\n",
+				clk_proto[i].name, PTR_ERR(clk[i]));
+			clk[i] = NULL;
+		}
+	}
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+
+	/* For 13MHz osc valid output range of PLL is from 156MHz to 266.5MHz */
+	clk_set_rate(clk[LPC32XX_CLK_HCLK_PLL], 208000000);
+
+	/* Set 48MHz rate of USB PLL clock */
+	clk_set_rate(clk[LPC32XX_CLK_USB_PLL], 48000000);
+
+	/* These two clocks must be always on independently on consumers */
+	clk_prepare_enable(clk[LPC32XX_CLK_ARM]);
+	clk_prepare_enable(clk[LPC32XX_CLK_HCLK]);
+
+	/* Enable ARM VFP by default */
+	clk_prepare_enable(clk[LPC32XX_CLK_ARM_VFP]);
+
+	/* Disable enabled by default clocks for NAND MLC and SLC */
+	clk_mask_disable(&clk_hw_proto[LPC32XX_CLK_SLC].hw0.clk.hw);
+	clk_mask_disable(&clk_hw_proto[LPC32XX_CLK_MLC].hw0.clk.hw);
+}
+CLK_OF_DECLARE(lpc32xx_clk, "nxp,lpc3220-clk", lpc32xx_clk_init);
+
+static void __init lpc32xx_usb_clk_init(struct device_node *np)
+{
+	unsigned int i;
+
+	usb_clk_vbase = of_iomap(np, 0);
+	if (!usb_clk_vbase) {
+		pr_err("failed to map address range\n");
+		return;
+	}
+
+	for (i = 0; i < LPC32XX_USB_CLK_MAX; i++) {
+		usb_clk[i] = lpc32xx_clk_register(i + LPC32XX_CLK_USB_OFFSET);
+		if (IS_ERR(usb_clk[i])) {
+			pr_err("failed to register %s clock: %ld\n",
+				clk_proto[i].name, PTR_ERR(usb_clk[i]));
+			usb_clk[i] = NULL;
+		}
+	}
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, &usb_clk_data);
+}
+CLK_OF_DECLARE(lpc32xx_usb_clk, "nxp,lpc3220-usb-clk", lpc32xx_usb_clk_init);
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index ee4c83a..b552ece 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -106,3 +106,20 @@
 	  Support for the multimedia clock controller on msm8974 devices.
 	  Say Y if you want to support multimedia devices such as display,
 	  graphics, video encode/decode, camera, etc.
+
+config MSM_GCC_8996
+	tristate "MSM8996 Global Clock Controller"
+	depends on COMMON_CLK_QCOM
+	help
+	  Support for the global clock controller on msm8996 devices.
+	  Say Y if you want to use peripheral devices such as UART, SPI,
+	  i2c, USB, UFS, SD/eMMC, PCIe, etc.
+
+config MSM_MMCC_8996
+	tristate "MSM8996 Multimedia Clock Controller"
+	select MSM_GCC_8996
+	depends on COMMON_CLK_QCOM
+	help
+	  Support for the multimedia clock controller on msm8996 devices.
+	  Say Y if you want to support multimedia devices such as display,
+	  graphics, video encode/decode, camera, etc.
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index fe62523..dc4280b 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -2,6 +2,7 @@
 
 clk-qcom-y += common.o
 clk-qcom-y += clk-regmap.o
+clk-qcom-y += clk-alpha-pll.o
 clk-qcom-y += clk-pll.o
 clk-qcom-y += clk-rcg.o
 clk-qcom-y += clk-rcg2.o
@@ -20,5 +21,7 @@
 obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o
 obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
 obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o
+obj-$(CONFIG_MSM_GCC_8996) += gcc-msm8996.o
 obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
 obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
+obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
new file mode 100644
index 0000000..e6a03ea
--- /dev/null
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+
+#include "clk-alpha-pll.h"
+
+#define PLL_MODE		0x00
+# define PLL_OUTCTRL		BIT(0)
+# define PLL_BYPASSNL		BIT(1)
+# define PLL_RESET_N		BIT(2)
+# define PLL_LOCK_COUNT_SHIFT	8
+# define PLL_LOCK_COUNT_MASK	0x3f
+# define PLL_BIAS_COUNT_SHIFT	14
+# define PLL_BIAS_COUNT_MASK	0x3f
+# define PLL_VOTE_FSM_ENA	BIT(20)
+# define PLL_VOTE_FSM_RESET	BIT(21)
+# define PLL_ACTIVE_FLAG	BIT(30)
+# define PLL_LOCK_DET		BIT(31)
+
+#define PLL_L_VAL		0x04
+#define PLL_ALPHA_VAL		0x08
+#define PLL_ALPHA_VAL_U		0x0c
+
+#define PLL_USER_CTL		0x10
+# define PLL_POST_DIV_SHIFT	8
+# define PLL_POST_DIV_MASK	0xf
+# define PLL_ALPHA_EN		BIT(24)
+# define PLL_VCO_SHIFT		20
+# define PLL_VCO_MASK		0x3
+
+#define PLL_USER_CTL_U		0x14
+
+#define PLL_CONFIG_CTL		0x18
+#define PLL_TEST_CTL		0x1c
+#define PLL_TEST_CTL_U		0x20
+#define PLL_STATUS		0x24
+
+/*
+ * Even though 40 bits are present, use only 32 for ease of calculation.
+ */
+#define ALPHA_REG_BITWIDTH	40
+#define ALPHA_BITWIDTH		32
+
+#define to_clk_alpha_pll(_hw) container_of(to_clk_regmap(_hw), \
+					   struct clk_alpha_pll, clkr)
+
+#define to_clk_alpha_pll_postdiv(_hw) container_of(to_clk_regmap(_hw), \
+					   struct clk_alpha_pll_postdiv, clkr)
+
+static int wait_for_pll(struct clk_alpha_pll *pll)
+{
+	u32 val, mask, off;
+	int count;
+	int ret;
+	const char *name = clk_hw_get_name(&pll->clkr.hw);
+
+	off = pll->offset;
+	ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
+	if (ret)
+		return ret;
+
+	if (val & PLL_VOTE_FSM_ENA)
+		mask = PLL_ACTIVE_FLAG;
+	else
+		mask = PLL_LOCK_DET;
+
+	/* Wait for pll to enable. */
+	for (count = 100; count > 0; count--) {
+		ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
+		if (ret)
+			return ret;
+		if ((val & mask) == mask)
+			return 0;
+
+		udelay(1);
+	}
+
+	WARN(1, "%s didn't enable after voting for it!\n", name);
+	return -ETIMEDOUT;
+}
+
+static int clk_alpha_pll_enable(struct clk_hw *hw)
+{
+	int ret;
+	struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+	u32 val, mask, off;
+
+	off = pll->offset;
+
+	mask = PLL_OUTCTRL | PLL_RESET_N | PLL_BYPASSNL;
+	ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
+	if (ret)
+		return ret;
+
+	/* If in FSM mode, just vote for it */
+	if (val & PLL_VOTE_FSM_ENA) {
+		ret = clk_enable_regmap(hw);
+		if (ret)
+			return ret;
+		return wait_for_pll(pll);
+	}
+
+	/* Skip if already enabled */
+	if ((val & mask) == mask)
+		return 0;
+
+	ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
+				 PLL_BYPASSNL, PLL_BYPASSNL);
+	if (ret)
+		return ret;
+
+	/*
+	 * H/W requires a 5us delay between disabling the bypass and
+	 * de-asserting the reset.
+	 */
+	mb();
+	udelay(5);
+
+	ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
+				 PLL_RESET_N, PLL_RESET_N);
+	if (ret)
+		return ret;
+
+	ret = wait_for_pll(pll);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
+				 PLL_OUTCTRL, PLL_OUTCTRL);
+
+	/* Ensure that the write above goes through before returning. */
+	mb();
+	return ret;
+}
+
+static void clk_alpha_pll_disable(struct clk_hw *hw)
+{
+	int ret;
+	struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+	u32 val, mask, off;
+
+	off = pll->offset;
+
+	ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
+	if (ret)
+		return;
+
+	/* If in FSM mode, just unvote it */
+	if (val & PLL_VOTE_FSM_ENA) {
+		clk_disable_regmap(hw);
+		return;
+	}
+
+	mask = PLL_OUTCTRL;
+	regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, mask, 0);
+
+	/* Delay of 2 output clock ticks required until output is disabled */
+	mb();
+	udelay(1);
+
+	mask = PLL_RESET_N | PLL_BYPASSNL;
+	regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, mask, 0);
+}
+
+static unsigned long alpha_pll_calc_rate(u64 prate, u32 l, u32 a)
+{
+	return (prate * l) + ((prate * a) >> ALPHA_BITWIDTH);
+}
+
+static unsigned long
+alpha_pll_round_rate(unsigned long rate, unsigned long prate, u32 *l, u64 *a)
+{
+	u64 remainder;
+	u64 quotient;
+
+	quotient = rate;
+	remainder = do_div(quotient, prate);
+	*l = quotient;
+
+	if (!remainder) {
+		*a = 0;
+		return rate;
+	}
+
+	/* Upper ALPHA_BITWIDTH bits of Alpha */
+	quotient = remainder << ALPHA_BITWIDTH;
+	remainder = do_div(quotient, prate);
+
+	if (remainder)
+		quotient++;
+
+	*a = quotient;
+	return alpha_pll_calc_rate(prate, *l, *a);
+}
+
+static const struct pll_vco *
+alpha_pll_find_vco(const struct clk_alpha_pll *pll, unsigned long rate)
+{
+	const struct pll_vco *v = pll->vco_table;
+	const struct pll_vco *end = v + pll->num_vco;
+
+	for (; v < end; v++)
+		if (rate >= v->min_freq && rate <= v->max_freq)
+			return v;
+
+	return NULL;
+}
+
+static unsigned long
+clk_alpha_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	u32 l, low, high, ctl;
+	u64 a = 0, prate = parent_rate;
+	struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+	u32 off = pll->offset;
+
+	regmap_read(pll->clkr.regmap, off + PLL_L_VAL, &l);
+
+	regmap_read(pll->clkr.regmap, off + PLL_USER_CTL, &ctl);
+	if (ctl & PLL_ALPHA_EN) {
+		regmap_read(pll->clkr.regmap, off + PLL_ALPHA_VAL, &low);
+		regmap_read(pll->clkr.regmap, off + PLL_ALPHA_VAL_U, &high);
+		a = (u64)high << 32 | low;
+		a >>= ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH;
+	}
+
+	return alpha_pll_calc_rate(prate, l, a);
+}
+
+static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+				  unsigned long prate)
+{
+	struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+	const struct pll_vco *vco;
+	u32 l, off = pll->offset;
+	u64 a;
+
+	rate = alpha_pll_round_rate(rate, prate, &l, &a);
+	vco = alpha_pll_find_vco(pll, rate);
+	if (!vco) {
+		pr_err("alpha pll not in a valid vco range\n");
+		return -EINVAL;
+	}
+
+	a <<= (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH);
+
+	regmap_write(pll->clkr.regmap, off + PLL_L_VAL, l);
+	regmap_write(pll->clkr.regmap, off + PLL_ALPHA_VAL, a);
+	regmap_write(pll->clkr.regmap, off + PLL_ALPHA_VAL_U, a >> 32);
+
+	regmap_update_bits(pll->clkr.regmap, off + PLL_USER_CTL,
+			   PLL_VCO_MASK << PLL_VCO_SHIFT,
+			   vco->val << PLL_VCO_SHIFT);
+
+	regmap_update_bits(pll->clkr.regmap, off + PLL_USER_CTL, PLL_ALPHA_EN,
+			   PLL_ALPHA_EN);
+
+	return 0;
+}
+
+static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+				     unsigned long *prate)
+{
+	struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+	u32 l;
+	u64 a;
+	unsigned long min_freq, max_freq;
+
+	rate = alpha_pll_round_rate(rate, *prate, &l, &a);
+	if (alpha_pll_find_vco(pll, rate))
+		return rate;
+
+	min_freq = pll->vco_table[0].min_freq;
+	max_freq = pll->vco_table[pll->num_vco - 1].max_freq;
+
+	return clamp(rate, min_freq, max_freq);
+}
+
+const struct clk_ops clk_alpha_pll_ops = {
+	.enable = clk_alpha_pll_enable,
+	.disable = clk_alpha_pll_disable,
+	.recalc_rate = clk_alpha_pll_recalc_rate,
+	.round_rate = clk_alpha_pll_round_rate,
+	.set_rate = clk_alpha_pll_set_rate,
+};
+EXPORT_SYMBOL_GPL(clk_alpha_pll_ops);
+
+static unsigned long
+clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw);
+	u32 ctl;
+
+	regmap_read(pll->clkr.regmap, pll->offset + PLL_USER_CTL, &ctl);
+
+	ctl >>= PLL_POST_DIV_SHIFT;
+	ctl &= PLL_POST_DIV_MASK;
+
+	return parent_rate >> fls(ctl);
+}
+
+static const struct clk_div_table clk_alpha_div_table[] = {
+	{ 0x0, 1 },
+	{ 0x1, 2 },
+	{ 0x3, 4 },
+	{ 0x7, 8 },
+	{ 0xf, 16 },
+	{ }
+};
+
+static long
+clk_alpha_pll_postdiv_round_rate(struct clk_hw *hw, unsigned long rate,
+				 unsigned long *prate)
+{
+	struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw);
+
+	return divider_round_rate(hw, rate, prate, clk_alpha_div_table,
+				  pll->width, CLK_DIVIDER_POWER_OF_TWO);
+}
+
+static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate,
+					  unsigned long parent_rate)
+{
+	struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw);
+	int div;
+
+	/* 16 -> 0xf, 8 -> 0x7, 4 -> 0x3, 2 -> 0x1, 1 -> 0x0 */
+	div = DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1;
+
+	return regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_USER_CTL,
+				  PLL_POST_DIV_MASK << PLL_POST_DIV_SHIFT,
+				  div << PLL_POST_DIV_SHIFT);
+}
+
+const struct clk_ops clk_alpha_pll_postdiv_ops = {
+	.recalc_rate = clk_alpha_pll_postdiv_recalc_rate,
+	.round_rate = clk_alpha_pll_postdiv_round_rate,
+	.set_rate = clk_alpha_pll_postdiv_set_rate,
+};
+EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_ops);
diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h
new file mode 100644
index 0000000..90ce201
--- /dev/null
+++ b/drivers/clk/qcom/clk-alpha-pll.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_CLK_ALPHA_PLL_H__
+#define __QCOM_CLK_ALPHA_PLL_H__
+
+#include <linux/clk-provider.h>
+#include "clk-regmap.h"
+
+struct pll_vco {
+	unsigned long min_freq;
+	unsigned long max_freq;
+	u32 val;
+};
+
+/**
+ * struct clk_alpha_pll - phase locked loop (PLL)
+ * @offset: base address of registers
+ * @vco_table: array of VCO settings
+ * @clkr: regmap clock handle
+ */
+struct clk_alpha_pll {
+	u32 offset;
+
+	const struct pll_vco *vco_table;
+	size_t num_vco;
+
+	struct clk_regmap clkr;
+};
+
+/**
+ * struct clk_alpha_pll_postdiv - phase locked loop (PLL) post-divider
+ * @offset: base address of registers
+ * @width: width of post-divider
+ * @clkr: regmap clock handle
+ */
+struct clk_alpha_pll_postdiv {
+	u32 offset;
+	u8 width;
+
+	struct clk_regmap clkr;
+};
+
+extern const struct clk_ops clk_alpha_pll_ops;
+extern const struct clk_ops clk_alpha_pll_postdiv_ops;
+
+#endif
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index 4b1e94b..b904c33 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -178,5 +178,6 @@
 extern const struct clk_ops clk_byte_ops;
 extern const struct clk_ops clk_byte2_ops;
 extern const struct clk_ops clk_pixel_ops;
+extern const struct clk_ops clk_gfx3d_ops;
 
 #endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index b544bb3..a071bba 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -723,3 +723,90 @@
 	.determine_rate = clk_pixel_determine_rate,
 };
 EXPORT_SYMBOL_GPL(clk_pixel_ops);
+
+static int clk_gfx3d_determine_rate(struct clk_hw *hw,
+				    struct clk_rate_request *req)
+{
+	struct clk_rate_request parent_req = { };
+	struct clk_hw *p2, *p8, *p9, *xo;
+	unsigned long p9_rate;
+	int ret;
+
+	xo = clk_hw_get_parent_by_index(hw, 0);
+	if (req->rate == clk_hw_get_rate(xo)) {
+		req->best_parent_hw = xo;
+		return 0;
+	}
+
+	p9 = clk_hw_get_parent_by_index(hw, 2);
+	p2 = clk_hw_get_parent_by_index(hw, 3);
+	p8 = clk_hw_get_parent_by_index(hw, 4);
+
+	/* PLL9 is a fixed rate PLL */
+	p9_rate = clk_hw_get_rate(p9);
+
+	parent_req.rate = req->rate = min(req->rate, p9_rate);
+	if (req->rate == p9_rate) {
+		req->rate = req->best_parent_rate = p9_rate;
+		req->best_parent_hw = p9;
+		return 0;
+	}
+
+	if (req->best_parent_hw == p9) {
+		/* Are we going back to a previously used rate? */
+		if (clk_hw_get_rate(p8) == req->rate)
+			req->best_parent_hw = p8;
+		else
+			req->best_parent_hw = p2;
+	} else if (req->best_parent_hw == p8) {
+		req->best_parent_hw = p2;
+	} else {
+		req->best_parent_hw = p8;
+	}
+
+	ret = __clk_determine_rate(req->best_parent_hw, &parent_req);
+	if (ret)
+		return ret;
+
+	req->rate = req->best_parent_rate = parent_req.rate;
+
+	return 0;
+}
+
+static int clk_gfx3d_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate, u8 index)
+{
+	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+	u32 cfg;
+	int ret;
+
+	/* Just mux it, we don't use the division or m/n hardware */
+	cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
+	ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg);
+	if (ret)
+		return ret;
+
+	return update_config(rcg);
+}
+
+static int clk_gfx3d_set_rate(struct clk_hw *hw, unsigned long rate,
+			      unsigned long parent_rate)
+{
+	/*
+	 * We should never get here; clk_gfx3d_determine_rate() should always
+	 * make us use a different parent than what we're currently using, so
+	 * clk_gfx3d_set_rate_and_parent() should always be called.
+	 */
+	return 0;
+}
+
+const struct clk_ops clk_gfx3d_ops = {
+	.is_enabled = clk_rcg2_is_enabled,
+	.get_parent = clk_rcg2_get_parent,
+	.set_parent = clk_rcg2_set_parent,
+	.recalc_rate = clk_rcg2_recalc_rate,
+	.set_rate = clk_gfx3d_set_rate,
+	.set_rate_and_parent = clk_gfx3d_set_rate_and_parent,
+	.determine_rate = clk_gfx3d_determine_rate,
+};
+EXPORT_SYMBOL_GPL(clk_gfx3d_ops);
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index 8fa4772..c112eba 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/clk-provider.h>
 #include <linux/reset-controller.h>
+#include <linux/of.h>
 
 #include "common.h"
 #include "clk-rcg.h"
@@ -88,6 +89,92 @@
 	gdsc_unregister(data);
 }
 
+/*
+ * Backwards compatibility with old DTs. Register a pass-through factor 1/1
+ * clock to translate 'path' clk into 'name' clk and regsiter the 'path'
+ * clk as a fixed rate clock if it isn't present.
+ */
+static int _qcom_cc_register_board_clk(struct device *dev, const char *path,
+				       const char *name, unsigned long rate,
+				       bool add_factor)
+{
+	struct device_node *node = NULL;
+	struct device_node *clocks_node;
+	struct clk_fixed_factor *factor;
+	struct clk_fixed_rate *fixed;
+	struct clk *clk;
+	struct clk_init_data init_data = { };
+
+	clocks_node = of_find_node_by_path("/clocks");
+	if (clocks_node)
+		node = of_find_node_by_name(clocks_node, path);
+	of_node_put(clocks_node);
+
+	if (!node) {
+		fixed = devm_kzalloc(dev, sizeof(*fixed), GFP_KERNEL);
+		if (!fixed)
+			return -EINVAL;
+
+		fixed->fixed_rate = rate;
+		fixed->hw.init = &init_data;
+
+		init_data.name = path;
+		init_data.flags = CLK_IS_ROOT;
+		init_data.ops = &clk_fixed_rate_ops;
+
+		clk = devm_clk_register(dev, &fixed->hw);
+		if (IS_ERR(clk))
+			return PTR_ERR(clk);
+	}
+	of_node_put(node);
+
+	if (add_factor) {
+		factor = devm_kzalloc(dev, sizeof(*factor), GFP_KERNEL);
+		if (!factor)
+			return -EINVAL;
+
+		factor->mult = factor->div = 1;
+		factor->hw.init = &init_data;
+
+		init_data.name = name;
+		init_data.parent_names = &path;
+		init_data.num_parents = 1;
+		init_data.flags = 0;
+		init_data.ops = &clk_fixed_factor_ops;
+
+		clk = devm_clk_register(dev, &factor->hw);
+		if (IS_ERR(clk))
+			return PTR_ERR(clk);
+	}
+
+	return 0;
+}
+
+int qcom_cc_register_board_clk(struct device *dev, const char *path,
+			       const char *name, unsigned long rate)
+{
+	bool add_factor = true;
+	struct device_node *node;
+
+	/* The RPM clock driver will add the factor clock if present */
+	if (IS_ENABLED(CONFIG_QCOM_RPMCC)) {
+		node = of_find_compatible_node(NULL, NULL, "qcom,rpmcc");
+		if (of_device_is_available(node))
+			add_factor = false;
+		of_node_put(node);
+	}
+
+	return _qcom_cc_register_board_clk(dev, path, name, rate, add_factor);
+}
+EXPORT_SYMBOL_GPL(qcom_cc_register_board_clk);
+
+int qcom_cc_register_sleep_clk(struct device *dev)
+{
+	return _qcom_cc_register_board_clk(dev, "sleep_clk", "sleep_clk_src",
+					   32768, true);
+}
+EXPORT_SYMBOL_GPL(qcom_cc_register_sleep_clk);
+
 int qcom_cc_really_probe(struct platform_device *pdev,
 			 const struct qcom_cc_desc *desc, struct regmap *regmap)
 {
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index 7c1fba3..ae9bdeb 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -37,6 +37,10 @@
 extern int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map,
 			       u8 src);
 
+extern int qcom_cc_register_board_clk(struct device *dev, const char *path,
+				      const char *name, unsigned long rate);
+extern int qcom_cc_register_sleep_clk(struct device *dev);
+
 extern struct regmap *qcom_cc_map(struct platform_device *pdev,
 				  const struct qcom_cc_desc *desc);
 extern int qcom_cc_really_probe(struct platform_device *pdev,
diff --git a/drivers/clk/qcom/gcc-apq8084.c b/drivers/clk/qcom/gcc-apq8084.c
index 1567c3a..cf73e53 100644
--- a/drivers/clk/qcom/gcc-apq8084.c
+++ b/drivers/clk/qcom/gcc-apq8084.c
@@ -3587,6 +3587,7 @@
 	.val_bits	= 32,
 	.max_register	= 0x1fc0,
 	.fast_io	= true,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc gcc_apq8084_desc = {
@@ -3607,18 +3608,16 @@
 
 static int gcc_apq8084_probe(struct platform_device *pdev)
 {
-	struct clk *clk;
+	int ret;
 	struct device *dev = &pdev->dev;
 
-	/* Temporary until RPM clocks supported */
-	clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000);
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
+	ret = qcom_cc_register_board_clk(dev, "xo_board", "xo", 19200000);
+	if (ret)
+		return ret;
 
-	clk = clk_register_fixed_rate(dev, "sleep_clk_src", NULL,
-				      CLK_IS_ROOT, 32768);
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
+	ret = qcom_cc_register_sleep_clk(dev);
+	if (ret)
+		return ret;
 
 	return qcom_cc_probe(pdev, &gcc_apq8084_desc);
 }
diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c
index 16fc64c..b692ae8 100644
--- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/drivers/clk/qcom/gcc-ipq806x.c
@@ -3005,6 +3005,7 @@
 	.val_bits	= 32,
 	.max_register	= 0x3e40,
 	.fast_io	= true,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc gcc_ipq806x_desc = {
@@ -3023,19 +3024,17 @@
 
 static int gcc_ipq806x_probe(struct platform_device *pdev)
 {
-	struct clk *clk;
 	struct device *dev = &pdev->dev;
 	struct regmap *regmap;
 	int ret;
 
-	/* Temporary until RPM clocks supported */
-	clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 25000000);
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
+	ret = qcom_cc_register_board_clk(dev, "cxo_board", "cxo", 19200000);
+	if (ret)
+		return ret;
 
-	clk = clk_register_fixed_rate(dev, "pxo", NULL, CLK_IS_ROOT, 25000000);
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
+	ret = qcom_cc_register_board_clk(dev, "pxo_board", "pxo", 27000000);
+	if (ret)
+		return ret;
 
 	ret = qcom_cc_probe(pdev, &gcc_ipq806x_desc);
 	if (ret)
diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c
index f110bb5..f6a2b14 100644
--- a/drivers/clk/qcom/gcc-msm8660.c
+++ b/drivers/clk/qcom/gcc-msm8660.c
@@ -2702,6 +2702,7 @@
 	.val_bits	= 32,
 	.max_register	= 0x363c,
 	.fast_io	= true,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc gcc_msm8660_desc = {
@@ -2720,17 +2721,16 @@
 
 static int gcc_msm8660_probe(struct platform_device *pdev)
 {
-	struct clk *clk;
+	int ret;
 	struct device *dev = &pdev->dev;
 
-	/* Temporary until RPM clocks supported */
-	clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000);
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
+	ret = qcom_cc_register_board_clk(dev, "cxo_board", "cxo", 19200000);
+	if (ret)
+		return ret;
 
-	clk = clk_register_fixed_rate(dev, "pxo", NULL, CLK_IS_ROOT, 27000000);
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
+	ret = qcom_cc_register_board_clk(dev, "pxo_board", "pxo", 27000000);
+	if (ret)
+		return ret;
 
 	return qcom_cc_probe(pdev, &gcc_msm8660_desc);
 }
diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c
index d0a0313..e3bf09d 100644
--- a/drivers/clk/qcom/gcc-msm8916.c
+++ b/drivers/clk/qcom/gcc-msm8916.c
@@ -3336,6 +3336,7 @@
 	.val_bits	= 32,
 	.max_register	= 0x80000,
 	.fast_io	= true,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc gcc_msm8916_desc = {
@@ -3356,18 +3357,16 @@
 
 static int gcc_msm8916_probe(struct platform_device *pdev)
 {
-	struct clk *clk;
+	int ret;
 	struct device *dev = &pdev->dev;
 
-	/* Temporary until RPM clocks supported */
-	clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000);
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
+	ret = qcom_cc_register_board_clk(dev, "xo_board", "xo", 19200000);
+	if (ret)
+		return ret;
 
-	clk = clk_register_fixed_rate(dev, "sleep_clk_src", NULL,
-				      CLK_IS_ROOT, 32768);
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
+	ret = qcom_cc_register_sleep_clk(dev);
+	if (ret)
+		return ret;
 
 	return qcom_cc_probe(pdev, &gcc_msm8916_desc);
 }
diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c
index 66c18bc..f31111e 100644
--- a/drivers/clk/qcom/gcc-msm8960.c
+++ b/drivers/clk/qcom/gcc-msm8960.c
@@ -3468,6 +3468,7 @@
 	.val_bits	= 32,
 	.max_register	= 0x3660,
 	.fast_io	= true,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct regmap_config gcc_apq8064_regmap_config = {
@@ -3476,6 +3477,7 @@
 	.val_bits	= 32,
 	.max_register	= 0x3880,
 	.fast_io	= true,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc gcc_msm8960_desc = {
@@ -3503,7 +3505,6 @@
 
 static int gcc_msm8960_probe(struct platform_device *pdev)
 {
-	struct clk *clk;
 	struct device *dev = &pdev->dev;
 	const struct of_device_id *match;
 	struct platform_device *tsens;
@@ -3513,14 +3514,13 @@
 	if (!match)
 		return -EINVAL;
 
-	/* Temporary until RPM clocks supported */
-	clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000);
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
+	ret = qcom_cc_register_board_clk(dev, "cxo_board", "cxo", 19200000);
+	if (ret)
+		return ret;
 
-	clk = clk_register_fixed_rate(dev, "pxo", NULL, CLK_IS_ROOT, 27000000);
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
+	ret = qcom_cc_register_board_clk(dev, "pxo_board", "pxo", 27000000);
+	if (ret)
+		return ret;
 
 	ret = qcom_cc_probe(pdev, match->data);
 	if (ret)
diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c
index 28abb8f..df164d6 100644
--- a/drivers/clk/qcom/gcc-msm8974.c
+++ b/drivers/clk/qcom/gcc-msm8974.c
@@ -2680,6 +2680,7 @@
 	.val_bits	= 32,
 	.max_register	= 0x1fc0,
 	.fast_io	= true,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc gcc_msm8974_desc = {
@@ -2717,7 +2718,7 @@
 
 static int gcc_msm8974_probe(struct platform_device *pdev)
 {
-	struct clk *clk;
+	int ret;
 	struct device *dev = &pdev->dev;
 	bool pro;
 	const struct of_device_id *id;
@@ -2730,16 +2731,13 @@
 	if (pro)
 		msm8974_pro_clock_override();
 
-	/* Temporary until RPM clocks supported */
-	clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000);
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
+	ret = qcom_cc_register_board_clk(dev, "xo_board", "xo", 19200000);
+	if (ret)
+		return ret;
 
-	/* Should move to DT node? */
-	clk = clk_register_fixed_rate(dev, "sleep_clk_src", NULL,
-				      CLK_IS_ROOT, 32768);
-	if (IS_ERR(clk))
-		return PTR_ERR(clk);
+	ret = qcom_cc_register_sleep_clk(dev);
+	if (ret)
+		return ret;
 
 	return qcom_cc_probe(pdev, &gcc_msm8974_desc);
 }
diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c
new file mode 100644
index 0000000..16d7c32
--- /dev/null
+++ b/drivers/clk/qcom/gcc-msm8996.c
@@ -0,0 +1,3422 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/clock/qcom,gcc-msm8996.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-alpha-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "reset.h"
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+
+enum {
+	P_XO,
+	P_GPLL0,
+	P_GPLL2,
+	P_GPLL3,
+	P_GPLL1,
+	P_GPLL2_EARLY,
+	P_GPLL0_EARLY_DIV,
+	P_SLEEP_CLK,
+	P_GPLL4,
+	P_AUD_REF_CLK,
+	P_GPLL1_EARLY_DIV
+};
+
+static const struct parent_map gcc_sleep_clk_map[] = {
+	{ P_SLEEP_CLK, 5 }
+};
+
+static const char * const gcc_sleep_clk[] = {
+	"sleep_clk"
+};
+
+static const struct parent_map gcc_xo_gpll0_map[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 }
+};
+
+static const char * const gcc_xo_gpll0[] = {
+	"xo",
+	"gpll0"
+};
+
+static const struct parent_map gcc_xo_sleep_clk_map[] = {
+	{ P_XO, 0 },
+	{ P_SLEEP_CLK, 5 }
+};
+
+static const char * const gcc_xo_sleep_clk[] = {
+	"xo",
+	"sleep_clk"
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll0_early_div_map[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL0_EARLY_DIV, 6 }
+};
+
+static const char * const gcc_xo_gpll0_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"gpll0_early_div"
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll4_map[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL4, 5 }
+};
+
+static const char * const gcc_xo_gpll0_gpll4[] = {
+	"xo",
+	"gpll0",
+	"gpll4"
+};
+
+static const struct parent_map gcc_xo_gpll0_aud_ref_clk_map[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_AUD_REF_CLK, 2 }
+};
+
+static const char * const gcc_xo_gpll0_aud_ref_clk[] = {
+	"xo",
+	"gpll0",
+	"aud_ref_clk"
+};
+
+static const struct parent_map gcc_xo_gpll0_sleep_clk_gpll0_early_div_map[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_SLEEP_CLK, 5 },
+	{ P_GPLL0_EARLY_DIV, 6 }
+};
+
+static const char * const gcc_xo_gpll0_sleep_clk_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"sleep_clk",
+	"gpll0_early_div"
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll4_gpll0_early_div_map[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL4, 5 },
+	{ P_GPLL0_EARLY_DIV, 6 }
+};
+
+static const char * const gcc_xo_gpll0_gpll4_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"gpll4",
+	"gpll0_early_div"
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div_map[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL2, 2 },
+	{ P_GPLL3, 3 },
+	{ P_GPLL0_EARLY_DIV, 6 }
+};
+
+static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"gpll2",
+	"gpll3",
+	"gpll0_early_div"
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div_map[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL1_EARLY_DIV, 3 },
+	{ P_GPLL1, 4 },
+	{ P_GPLL4, 5 },
+	{ P_GPLL0_EARLY_DIV, 6 }
+};
+
+static const char * const gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"gpll1_early_div",
+	"gpll1",
+	"gpll4",
+	"gpll0_early_div"
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll2_early_gpll0_early_div_map[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL2, 2 },
+	{ P_GPLL3, 3 },
+	{ P_GPLL1, 4 },
+	{ P_GPLL2_EARLY, 5 },
+	{ P_GPLL0_EARLY_DIV, 6 }
+};
+
+static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll2_early_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"gpll2",
+	"gpll3",
+	"gpll1",
+	"gpll2_early",
+	"gpll0_early_div"
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div_map[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL2, 2 },
+	{ P_GPLL3, 3 },
+	{ P_GPLL1, 4 },
+	{ P_GPLL4, 5 },
+	{ P_GPLL0_EARLY_DIV, 6 }
+};
+
+static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"gpll2",
+	"gpll3",
+	"gpll1",
+	"gpll4",
+	"gpll0_early_div"
+};
+
+static struct clk_fixed_factor xo = {
+	.mult = 1,
+	.div = 1,
+	.hw.init = &(struct clk_init_data){
+		.name = "xo",
+		.parent_names = (const char *[]){ "xo_board" },
+		.num_parents = 1,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_alpha_pll gpll0_early = {
+	.offset = 0x00000,
+	.clkr = {
+		.enable_reg = 0x52000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpll0_early",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_ops,
+		},
+	},
+};
+
+static struct clk_fixed_factor gpll0_early_div = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "gpll0_early_div",
+		.parent_names = (const char *[]){ "gpll0_early" },
+		.num_parents = 1,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_alpha_pll_postdiv gpll0 = {
+	.offset = 0x00000,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gpll0",
+		.parent_names = (const char *[]){ "gpll0_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+	},
+};
+
+static struct clk_alpha_pll gpll4_early = {
+	.offset = 0x77000,
+	.clkr = {
+		.enable_reg = 0x52000,
+		.enable_mask = BIT(4),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpll4_early",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_ops,
+		},
+	},
+};
+
+static struct clk_alpha_pll_postdiv gpll4 = {
+	.offset = 0x77000,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gpll4",
+		.parent_names = (const char *[]){ "gpll4_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_system_noc_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(240000000, P_GPLL0, 2.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 system_noc_clk_src = {
+	.cmd_rcgr = 0x0401c,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll2_early_gpll0_early_div_map,
+	.freq_tbl = ftbl_system_noc_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "system_noc_clk_src",
+		.parent_names = gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll2_early_gpll0_early_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_config_noc_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(37500000, P_GPLL0, 16, 0, 0),
+	F(75000000, P_GPLL0, 8, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 config_noc_clk_src = {
+	.cmd_rcgr = 0x0500c,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_config_noc_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "config_noc_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_periph_noc_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(37500000, P_GPLL0, 16, 0, 0),
+	F(50000000, P_GPLL0, 12, 0, 0),
+	F(75000000, P_GPLL0, 8, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 periph_noc_clk_src = {
+	.cmd_rcgr = 0x06014,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_periph_noc_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "periph_noc_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb30_master_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(120000000, P_GPLL0, 5, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb30_master_clk_src = {
+	.cmd_rcgr = 0x0f014,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_gpll0_early_div_map,
+	.freq_tbl = ftbl_usb30_master_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb30_master_clk_src",
+		.parent_names = gcc_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb30_mock_utmi_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb30_mock_utmi_clk_src = {
+	.cmd_rcgr = 0x0f028,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_gpll0_early_div_map,
+	.freq_tbl = ftbl_usb30_mock_utmi_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb30_mock_utmi_clk_src",
+		.parent_names = gcc_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb3_phy_aux_clk_src[] = {
+	F(1200000, P_XO, 16, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb3_phy_aux_clk_src = {
+	.cmd_rcgr = 0x5000c,
+	.hid_width = 5,
+	.parent_map = gcc_xo_sleep_clk_map,
+	.freq_tbl = ftbl_usb3_phy_aux_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb3_phy_aux_clk_src",
+		.parent_names = gcc_xo_sleep_clk,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb20_master_clk_src[] = {
+	F(120000000, P_GPLL0, 5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb20_master_clk_src = {
+	.cmd_rcgr = 0x12010,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_gpll0_early_div_map,
+	.freq_tbl = ftbl_usb20_master_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb20_master_clk_src",
+		.parent_names = gcc_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 usb20_mock_utmi_clk_src = {
+	.cmd_rcgr = 0x12024,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_gpll0_early_div_map,
+	.freq_tbl = ftbl_usb30_mock_utmi_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb20_mock_utmi_clk_src",
+		.parent_names = gcc_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_sdcc1_apps_clk_src[] = {
+	F(144000, P_XO, 16, 3, 25),
+	F(400000, P_XO, 12, 1, 4),
+	F(20000000, P_GPLL0, 15, 1, 2),
+	F(25000000, P_GPLL0, 12, 1, 2),
+	F(50000000, P_GPLL0, 12, 0, 0),
+	F(96000000, P_GPLL4, 4, 0, 0),
+	F(192000000, P_GPLL4, 2, 0, 0),
+	F(384000000, P_GPLL4, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 sdcc1_apps_clk_src = {
+	.cmd_rcgr = 0x13010,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_gpll4_gpll0_early_div_map,
+	.freq_tbl = ftbl_sdcc1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "sdcc1_apps_clk_src",
+		.parent_names = gcc_xo_gpll0_gpll4_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 sdcc1_ice_core_clk_src = {
+	.cmd_rcgr = 0x13024,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_gpll4_gpll0_early_div_map,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "sdcc1_ice_core_clk_src",
+		.parent_names = gcc_xo_gpll0_gpll4_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_sdcc2_apps_clk_src[] = {
+	F(144000, P_XO, 16, 3, 25),
+	F(400000, P_XO, 12, 1, 4),
+	F(20000000, P_GPLL0, 15, 1, 2),
+	F(25000000, P_GPLL0, 12, 1, 2),
+	F(50000000, P_GPLL0, 12, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 sdcc2_apps_clk_src = {
+	.cmd_rcgr = 0x14010,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_gpll4_map,
+	.freq_tbl = ftbl_sdcc2_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "sdcc2_apps_clk_src",
+		.parent_names = gcc_xo_gpll0_gpll4,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 sdcc3_apps_clk_src = {
+	.cmd_rcgr = 0x15010,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_gpll4_map,
+	.freq_tbl = ftbl_sdcc2_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "sdcc3_apps_clk_src",
+		.parent_names = gcc_xo_gpll0_gpll4,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_sdcc4_apps_clk_src[] = {
+	F(144000, P_XO, 16, 3, 25),
+	F(400000, P_XO, 12, 1, 4),
+	F(20000000, P_GPLL0, 15, 1, 2),
+	F(25000000, P_GPLL0, 12, 1, 2),
+	F(50000000, P_GPLL0, 12, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 sdcc4_apps_clk_src = {
+	.cmd_rcgr = 0x16010,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_sdcc4_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "sdcc4_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_blsp1_qup1_spi_apps_clk_src[] = {
+	F(960000, P_XO, 10, 1, 2),
+	F(4800000, P_XO, 4, 0, 0),
+	F(9600000, P_XO, 2, 0, 0),
+	F(15000000, P_GPLL0, 10, 1, 4),
+	F(19200000, P_XO, 1, 0, 0),
+	F(25000000, P_GPLL0, 12, 1, 2),
+	F(50000000, P_GPLL0, 12, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1900c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup1_spi_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_blsp1_qup1_i2c_apps_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(50000000, P_GPLL0, 12, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x19020,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup1_i2c_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_blsp1_uart1_apps_clk_src[] = {
+	F(3686400, P_GPLL0, 1, 96, 15625),
+	F(7372800, P_GPLL0, 1, 192, 15625),
+	F(14745600, P_GPLL0, 1, 384, 15625),
+	F(16000000, P_GPLL0, 5, 2, 15),
+	F(19200000, P_XO, 1, 0, 0),
+	F(24000000, P_GPLL0, 5, 1, 5),
+	F(32000000, P_GPLL0, 1, 4, 75),
+	F(40000000, P_GPLL0, 15, 0, 0),
+	F(46400000, P_GPLL0, 1, 29, 375),
+	F(48000000, P_GPLL0, 12.5, 0, 0),
+	F(51200000, P_GPLL0, 1, 32, 375),
+	F(56000000, P_GPLL0, 1, 7, 75),
+	F(58982400, P_GPLL0, 1, 1536, 15625),
+	F(60000000, P_GPLL0, 10, 0, 0),
+	F(63157895, P_GPLL0, 9.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 blsp1_uart1_apps_clk_src = {
+	.cmd_rcgr = 0x1a00c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_uart1_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1b00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup2_spi_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x1b020,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup2_i2c_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_uart2_apps_clk_src = {
+	.cmd_rcgr = 0x1c00c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_uart2_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1d00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup3_spi_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x1d020,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup3_i2c_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_uart3_apps_clk_src = {
+	.cmd_rcgr = 0x1e00c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_uart3_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1f00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup4_spi_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x1f020,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup4_i2c_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_uart4_apps_clk_src = {
+	.cmd_rcgr = 0x2000c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_uart4_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup5_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2100c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup5_spi_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup5_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x21020,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup5_i2c_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_uart5_apps_clk_src = {
+	.cmd_rcgr = 0x2200c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_uart5_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup6_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2300c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup6_spi_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup6_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x23020,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup6_i2c_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_uart6_apps_clk_src = {
+	.cmd_rcgr = 0x2400c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_uart6_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup1_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2600c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup1_spi_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x26020,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup1_i2c_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_uart1_apps_clk_src = {
+	.cmd_rcgr = 0x2700c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_uart1_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup2_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2800c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup2_spi_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x28020,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup2_i2c_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_uart2_apps_clk_src = {
+	.cmd_rcgr = 0x2900c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_uart2_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup3_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2a00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup3_spi_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x2a020,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup3_i2c_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_uart3_apps_clk_src = {
+	.cmd_rcgr = 0x2b00c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_uart3_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup4_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2c00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup4_spi_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x2c020,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup4_i2c_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_uart4_apps_clk_src = {
+	.cmd_rcgr = 0x2d00c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_uart4_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup5_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2e00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup5_spi_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup5_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x2e020,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup5_i2c_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_uart5_apps_clk_src = {
+	.cmd_rcgr = 0x2f00c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_uart5_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup6_spi_apps_clk_src = {
+	.cmd_rcgr = 0x3000c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup6_spi_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup6_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x30020,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup6_i2c_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_uart6_apps_clk_src = {
+	.cmd_rcgr = 0x3100c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_uart6_apps_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_pdm2_clk_src[] = {
+	F(60000000, P_GPLL0, 10, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 pdm2_clk_src = {
+	.cmd_rcgr = 0x33010,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_pdm2_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "pdm2_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_tsif_ref_clk_src[] = {
+	F(105495, P_XO, 1, 1, 182),
+	{ }
+};
+
+static struct clk_rcg2 tsif_ref_clk_src = {
+	.cmd_rcgr = 0x36010,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_aud_ref_clk_map,
+	.freq_tbl = ftbl_tsif_ref_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "tsif_ref_clk_src",
+		.parent_names = gcc_xo_gpll0_aud_ref_clk,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 gcc_sleep_clk_src = {
+	.cmd_rcgr = 0x43014,
+	.hid_width = 5,
+	.parent_map = gcc_sleep_clk_map,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gcc_sleep_clk_src",
+		.parent_names = gcc_sleep_clk,
+		.num_parents = 1,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 hmss_rbcpr_clk_src = {
+	.cmd_rcgr = 0x48040,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_usb30_mock_utmi_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "hmss_rbcpr_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 hmss_gpll0_clk_src = {
+	.cmd_rcgr = 0x48058,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "hmss_gpll0_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_gp1_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 gp1_clk_src = {
+	.cmd_rcgr = 0x64004,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_sleep_clk_gpll0_early_div_map,
+	.freq_tbl = ftbl_gp1_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gp1_clk_src",
+		.parent_names = gcc_xo_gpll0_sleep_clk_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 gp2_clk_src = {
+	.cmd_rcgr = 0x65004,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_sleep_clk_gpll0_early_div_map,
+	.freq_tbl = ftbl_gp1_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gp2_clk_src",
+		.parent_names = gcc_xo_gpll0_sleep_clk_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 gp3_clk_src = {
+	.cmd_rcgr = 0x66004,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_sleep_clk_gpll0_early_div_map,
+	.freq_tbl = ftbl_gp1_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gp3_clk_src",
+		.parent_names = gcc_xo_gpll0_sleep_clk_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_pcie_aux_clk_src[] = {
+	F(1010526, P_XO, 1, 1, 19),
+	{ }
+};
+
+static struct clk_rcg2 pcie_aux_clk_src = {
+	.cmd_rcgr = 0x6c000,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_xo_sleep_clk_map,
+	.freq_tbl = ftbl_pcie_aux_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "pcie_aux_clk_src",
+		.parent_names = gcc_xo_sleep_clk,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_ufs_axi_clk_src[] = {
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(240000000, P_GPLL0, 2.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ufs_axi_clk_src = {
+	.cmd_rcgr = 0x75024,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.freq_tbl = ftbl_ufs_axi_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "ufs_axi_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 ufs_ice_core_clk_src = {
+	.cmd_rcgr = 0x76014,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_map,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "ufs_ice_core_clk_src",
+		.parent_names = gcc_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 qspi_ser_clk_src = {
+	.cmd_rcgr = 0x8b00c,
+	.hid_width = 5,
+	.parent_map = gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div_map,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "qspi_ser_clk_src",
+		.parent_names = gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div,
+		.num_parents = 6,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_branch gcc_sys_noc_usb3_axi_clk = {
+	.halt_reg = 0x0f03c,
+	.clkr = {
+		.enable_reg = 0x0f03c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sys_noc_usb3_axi_clk",
+			.parent_names = (const char *[]){ "usb30_master_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sys_noc_ufs_axi_clk = {
+	.halt_reg = 0x75038,
+	.clkr = {
+		.enable_reg = 0x75038,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sys_noc_ufs_axi_clk",
+			.parent_names = (const char *[]){ "ufs_axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_periph_noc_usb20_ahb_clk = {
+	.halt_reg = 0x6010,
+	.clkr = {
+		.enable_reg = 0x6010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_periph_noc_usb20_ahb_clk",
+			.parent_names = (const char *[]){ "usb20_master_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mmss_noc_cfg_ahb_clk = {
+	.halt_reg = 0x9008,
+	.clkr = {
+		.enable_reg = 0x9008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mmss_noc_cfg_ahb_clk",
+			.parent_names = (const char *[]){ "config_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mmss_bimc_gfx_clk = {
+	.halt_reg = 0x9010,
+	.clkr = {
+		.enable_reg = 0x9010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mmss_bimc_gfx_clk",
+			.flags = CLK_SET_RATE_PARENT | CLK_IS_ROOT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb30_master_clk = {
+	.halt_reg = 0x0f008,
+	.clkr = {
+		.enable_reg = 0x0f008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb30_master_clk",
+			.parent_names = (const char *[]){ "usb30_master_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb30_sleep_clk = {
+	.halt_reg = 0x0f00c,
+	.clkr = {
+		.enable_reg = 0x0f00c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb30_sleep_clk",
+			.parent_names = (const char *[]){ "gcc_sleep_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb30_mock_utmi_clk = {
+	.halt_reg = 0x0f010,
+	.clkr = {
+		.enable_reg = 0x0f010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb30_mock_utmi_clk",
+			.parent_names = (const char *[]){ "usb30_mock_utmi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb3_phy_aux_clk = {
+	.halt_reg = 0x50000,
+	.clkr = {
+		.enable_reg = 0x50000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb3_phy_aux_clk",
+			.parent_names = (const char *[]){ "usb3_phy_aux_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb3_phy_pipe_clk = {
+	.halt_reg = 0x50004,
+	.clkr = {
+		.enable_reg = 0x50004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb3_phy_pipe_clk",
+			.parent_names = (const char *[]){ "usb3_phy_pipe_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb20_master_clk = {
+	.halt_reg = 0x12004,
+	.clkr = {
+		.enable_reg = 0x12004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb20_master_clk",
+			.parent_names = (const char *[]){ "usb20_master_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb20_sleep_clk = {
+	.halt_reg = 0x12008,
+	.clkr = {
+		.enable_reg = 0x12008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb20_sleep_clk",
+			.parent_names = (const char *[]){ "gcc_sleep_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb20_mock_utmi_clk = {
+	.halt_reg = 0x1200c,
+	.clkr = {
+		.enable_reg = 0x1200c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb20_mock_utmi_clk",
+			.parent_names = (const char *[]){ "usb20_mock_utmi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = {
+	.halt_reg = 0x6a004,
+	.clkr = {
+		.enable_reg = 0x6a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb_phy_cfg_ahb2phy_clk",
+			.parent_names = (const char *[]){ "periph_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc1_apps_clk = {
+	.halt_reg = 0x13004,
+	.clkr = {
+		.enable_reg = 0x13004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc1_apps_clk",
+			.parent_names = (const char *[]){ "sdcc1_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+	.halt_reg = 0x13008,
+	.clkr = {
+		.enable_reg = 0x13008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc1_ahb_clk",
+			.parent_names = (const char *[]){ "periph_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc1_ice_core_clk = {
+	.halt_reg = 0x13038,
+	.clkr = {
+		.enable_reg = 0x13038,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc1_ice_core_clk",
+			.parent_names = (const char *[]){ "sdcc1_ice_core_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc2_apps_clk = {
+	.halt_reg = 0x14004,
+	.clkr = {
+		.enable_reg = 0x14004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc2_apps_clk",
+			.parent_names = (const char *[]){ "sdcc2_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc2_ahb_clk = {
+	.halt_reg = 0x14008,
+	.clkr = {
+		.enable_reg = 0x14008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc2_ahb_clk",
+			.parent_names = (const char *[]){ "periph_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc3_apps_clk = {
+	.halt_reg = 0x15004,
+	.clkr = {
+		.enable_reg = 0x15004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc3_apps_clk",
+			.parent_names = (const char *[]){ "sdcc3_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc3_ahb_clk = {
+	.halt_reg = 0x15008,
+	.clkr = {
+		.enable_reg = 0x15008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc3_ahb_clk",
+			.parent_names = (const char *[]){ "periph_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc4_apps_clk = {
+	.halt_reg = 0x16004,
+	.clkr = {
+		.enable_reg = 0x16004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc4_apps_clk",
+			.parent_names = (const char *[]){ "sdcc4_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc4_ahb_clk = {
+	.halt_reg = 0x16008,
+	.clkr = {
+		.enable_reg = 0x16008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc4_ahb_clk",
+			.parent_names = (const char *[]){ "periph_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_ahb_clk = {
+	.halt_reg = 0x17004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(17),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_ahb_clk",
+			.parent_names = (const char *[]){ "periph_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_sleep_clk = {
+	.halt_reg = 0x17008,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(16),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_sleep_clk",
+			.parent_names = (const char *[]){ "gcc_sleep_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = {
+	.halt_reg = 0x19004,
+	.clkr = {
+		.enable_reg = 0x19004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup1_spi_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_qup1_spi_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = {
+	.halt_reg = 0x19008,
+	.clkr = {
+		.enable_reg = 0x19008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup1_i2c_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_qup1_i2c_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_uart1_apps_clk = {
+	.halt_reg = 0x1a004,
+	.clkr = {
+		.enable_reg = 0x1a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_uart1_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_uart1_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = {
+	.halt_reg = 0x1b004,
+	.clkr = {
+		.enable_reg = 0x1b004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup2_spi_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_qup2_spi_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = {
+	.halt_reg = 0x1b008,
+	.clkr = {
+		.enable_reg = 0x1b008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup2_i2c_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_qup2_i2c_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_uart2_apps_clk = {
+	.halt_reg = 0x1c004,
+	.clkr = {
+		.enable_reg = 0x1c004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_uart2_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_uart2_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = {
+	.halt_reg = 0x1d004,
+	.clkr = {
+		.enable_reg = 0x1d004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup3_spi_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_qup3_spi_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = {
+	.halt_reg = 0x1d008,
+	.clkr = {
+		.enable_reg = 0x1d008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup3_i2c_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_qup3_i2c_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_uart3_apps_clk = {
+	.halt_reg = 0x1e004,
+	.clkr = {
+		.enable_reg = 0x1e004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_uart3_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_uart3_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = {
+	.halt_reg = 0x1f004,
+	.clkr = {
+		.enable_reg = 0x1f004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup4_spi_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_qup4_spi_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = {
+	.halt_reg = 0x1f008,
+	.clkr = {
+		.enable_reg = 0x1f008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup4_i2c_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_qup4_i2c_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_uart4_apps_clk = {
+	.halt_reg = 0x20004,
+	.clkr = {
+		.enable_reg = 0x20004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_uart4_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_uart4_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup5_spi_apps_clk = {
+	.halt_reg = 0x21004,
+	.clkr = {
+		.enable_reg = 0x21004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup5_spi_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_qup5_spi_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup5_i2c_apps_clk = {
+	.halt_reg = 0x21008,
+	.clkr = {
+		.enable_reg = 0x21008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup5_i2c_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_qup5_i2c_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_uart5_apps_clk = {
+	.halt_reg = 0x22004,
+	.clkr = {
+		.enable_reg = 0x22004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_uart5_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_uart5_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup6_spi_apps_clk = {
+	.halt_reg = 0x23004,
+	.clkr = {
+		.enable_reg = 0x23004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup6_spi_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_qup6_spi_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup6_i2c_apps_clk = {
+	.halt_reg = 0x23008,
+	.clkr = {
+		.enable_reg = 0x23008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup6_i2c_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_qup6_i2c_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_uart6_apps_clk = {
+	.halt_reg = 0x24004,
+	.clkr = {
+		.enable_reg = 0x24004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_uart6_apps_clk",
+			.parent_names = (const char *[]){ "blsp1_uart6_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_ahb_clk = {
+	.halt_reg = 0x25004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(15),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_ahb_clk",
+			.parent_names = (const char *[]){ "periph_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_sleep_clk = {
+	.halt_reg = 0x25008,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(14),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_sleep_clk",
+			.parent_names = (const char *[]){ "gcc_sleep_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup1_spi_apps_clk = {
+	.halt_reg = 0x26004,
+	.clkr = {
+		.enable_reg = 0x26004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup1_spi_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_qup1_spi_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup1_i2c_apps_clk = {
+	.halt_reg = 0x26008,
+	.clkr = {
+		.enable_reg = 0x26008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup1_i2c_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_qup1_i2c_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_uart1_apps_clk = {
+	.halt_reg = 0x27004,
+	.clkr = {
+		.enable_reg = 0x27004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_uart1_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_uart1_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup2_spi_apps_clk = {
+	.halt_reg = 0x28004,
+	.clkr = {
+		.enable_reg = 0x28004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup2_spi_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_qup2_spi_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup2_i2c_apps_clk = {
+	.halt_reg = 0x28008,
+	.clkr = {
+		.enable_reg = 0x28008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup2_i2c_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_qup2_i2c_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_uart2_apps_clk = {
+	.halt_reg = 0x29004,
+	.clkr = {
+		.enable_reg = 0x29004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_uart2_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_uart2_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup3_spi_apps_clk = {
+	.halt_reg = 0x2a004,
+	.clkr = {
+		.enable_reg = 0x2a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup3_spi_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_qup3_spi_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup3_i2c_apps_clk = {
+	.halt_reg = 0x2a008,
+	.clkr = {
+		.enable_reg = 0x2a008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup3_i2c_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_qup3_i2c_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_uart3_apps_clk = {
+	.halt_reg = 0x2b004,
+	.clkr = {
+		.enable_reg = 0x2b004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_uart3_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_uart3_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup4_spi_apps_clk = {
+	.halt_reg = 0x2c004,
+	.clkr = {
+		.enable_reg = 0x2c004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup4_spi_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_qup4_spi_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup4_i2c_apps_clk = {
+	.halt_reg = 0x2c008,
+	.clkr = {
+		.enable_reg = 0x2c008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup4_i2c_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_qup4_i2c_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_uart4_apps_clk = {
+	.halt_reg = 0x2d004,
+	.clkr = {
+		.enable_reg = 0x2d004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_uart4_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_uart4_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup5_spi_apps_clk = {
+	.halt_reg = 0x2e004,
+	.clkr = {
+		.enable_reg = 0x2e004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup5_spi_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_qup5_spi_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup5_i2c_apps_clk = {
+	.halt_reg = 0x2e008,
+	.clkr = {
+		.enable_reg = 0x2e008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup5_i2c_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_qup5_i2c_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_uart5_apps_clk = {
+	.halt_reg = 0x2f004,
+	.clkr = {
+		.enable_reg = 0x2f004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_uart5_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_uart5_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup6_spi_apps_clk = {
+	.halt_reg = 0x30004,
+	.clkr = {
+		.enable_reg = 0x30004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup6_spi_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_qup6_spi_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup6_i2c_apps_clk = {
+	.halt_reg = 0x30008,
+	.clkr = {
+		.enable_reg = 0x30008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup6_i2c_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_qup6_i2c_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_uart6_apps_clk = {
+	.halt_reg = 0x31004,
+	.clkr = {
+		.enable_reg = 0x31004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_uart6_apps_clk",
+			.parent_names = (const char *[]){ "blsp2_uart6_apps_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+	.halt_reg = 0x33004,
+	.clkr = {
+		.enable_reg = 0x33004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pdm_ahb_clk",
+			.parent_names = (const char *[]){ "periph_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+	.halt_reg = 0x3300c,
+	.clkr = {
+		.enable_reg = 0x3300c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pdm2_clk",
+			.parent_names = (const char *[]){ "pdm2_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_prng_ahb_clk = {
+	.halt_reg = 0x34004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(13),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_prng_ahb_clk",
+			.parent_names = (const char *[]){ "config_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_tsif_ahb_clk = {
+	.halt_reg = 0x36004,
+	.clkr = {
+		.enable_reg = 0x36004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_tsif_ahb_clk",
+			.parent_names = (const char *[]){ "periph_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_tsif_ref_clk = {
+	.halt_reg = 0x36008,
+	.clkr = {
+		.enable_reg = 0x36008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_tsif_ref_clk",
+			.parent_names = (const char *[]){ "tsif_ref_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_tsif_inactivity_timers_clk = {
+	.halt_reg = 0x3600c,
+	.clkr = {
+		.enable_reg = 0x3600c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_tsif_inactivity_timers_clk",
+			.parent_names = (const char *[]){ "gcc_sleep_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+	.halt_reg = 0x38004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(10),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_boot_rom_ahb_clk",
+			.parent_names = (const char *[]){ "config_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_bimc_gfx_clk = {
+	.halt_reg = 0x46018,
+	.clkr = {
+		.enable_reg = 0x46018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_bimc_gfx_clk",
+			.flags = CLK_SET_RATE_PARENT | CLK_IS_ROOT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_hmss_rbcpr_clk = {
+	.halt_reg = 0x4800c,
+	.clkr = {
+		.enable_reg = 0x4800c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_hmss_rbcpr_clk",
+			.parent_names = (const char *[]){ "hmss_rbcpr_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gp1_clk = {
+	.halt_reg = 0x64000,
+	.clkr = {
+		.enable_reg = 0x64000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gp1_clk",
+			.parent_names = (const char *[]){ "gp1_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gp2_clk = {
+	.halt_reg = 0x65000,
+	.clkr = {
+		.enable_reg = 0x65000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gp2_clk",
+			.parent_names = (const char *[]){ "gp2_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gp3_clk = {
+	.halt_reg = 0x66000,
+	.clkr = {
+		.enable_reg = 0x66000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gp3_clk",
+			.parent_names = (const char *[]){ "gp3_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_0_slv_axi_clk = {
+	.halt_reg = 0x6b008,
+	.clkr = {
+		.enable_reg = 0x6b008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_0_slv_axi_clk",
+			.parent_names = (const char *[]){ "system_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_0_mstr_axi_clk = {
+	.halt_reg = 0x6b00c,
+	.clkr = {
+		.enable_reg = 0x6b00c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_0_mstr_axi_clk",
+			.parent_names = (const char *[]){ "system_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_0_cfg_ahb_clk = {
+	.halt_reg = 0x6b010,
+	.clkr = {
+		.enable_reg = 0x6b010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_0_cfg_ahb_clk",
+			.parent_names = (const char *[]){ "config_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_0_aux_clk = {
+	.halt_reg = 0x6b014,
+	.clkr = {
+		.enable_reg = 0x6b014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_0_aux_clk",
+			.parent_names = (const char *[]){ "pcie_aux_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_0_pipe_clk = {
+	.halt_reg = 0x6b018,
+	.clkr = {
+		.enable_reg = 0x6b018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_0_pipe_clk",
+			.parent_names = (const char *[]){ "pcie_0_pipe_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_1_slv_axi_clk = {
+	.halt_reg = 0x6d008,
+	.clkr = {
+		.enable_reg = 0x6d008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_1_slv_axi_clk",
+			.parent_names = (const char *[]){ "system_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_1_mstr_axi_clk = {
+	.halt_reg = 0x6d00c,
+	.clkr = {
+		.enable_reg = 0x6d00c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_1_mstr_axi_clk",
+			.parent_names = (const char *[]){ "system_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_1_cfg_ahb_clk = {
+	.halt_reg = 0x6d010,
+	.clkr = {
+		.enable_reg = 0x6d010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_1_cfg_ahb_clk",
+			.parent_names = (const char *[]){ "config_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_1_aux_clk = {
+	.halt_reg = 0x6d014,
+	.clkr = {
+		.enable_reg = 0x6d014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_1_aux_clk",
+			.parent_names = (const char *[]){ "pcie_aux_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_1_pipe_clk = {
+	.halt_reg = 0x6d018,
+	.clkr = {
+		.enable_reg = 0x6d018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_1_pipe_clk",
+			.parent_names = (const char *[]){ "pcie_1_pipe_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_2_slv_axi_clk = {
+	.halt_reg = 0x6e008,
+	.clkr = {
+		.enable_reg = 0x6e008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_2_slv_axi_clk",
+			.parent_names = (const char *[]){ "system_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_2_mstr_axi_clk = {
+	.halt_reg = 0x6e00c,
+	.clkr = {
+		.enable_reg = 0x6e00c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_2_mstr_axi_clk",
+			.parent_names = (const char *[]){ "system_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_2_cfg_ahb_clk = {
+	.halt_reg = 0x6e010,
+	.clkr = {
+		.enable_reg = 0x6e010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_2_cfg_ahb_clk",
+			.parent_names = (const char *[]){ "config_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_2_aux_clk = {
+	.halt_reg = 0x6e014,
+	.clkr = {
+		.enable_reg = 0x6e014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_2_aux_clk",
+			.parent_names = (const char *[]){ "pcie_aux_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_2_pipe_clk = {
+	.halt_reg = 0x6e108,
+	.clkr = {
+		.enable_reg = 0x6e108,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_2_pipe_clk",
+			.parent_names = (const char *[]){ "pcie_2_pipe_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_phy_cfg_ahb_clk = {
+	.halt_reg = 0x6f004,
+	.clkr = {
+		.enable_reg = 0x6f004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_phy_cfg_ahb_clk",
+			.parent_names = (const char *[]){ "config_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_phy_aux_clk = {
+	.halt_reg = 0x6f008,
+	.clkr = {
+		.enable_reg = 0x6f008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_phy_aux_clk",
+			.parent_names = (const char *[]){ "pcie_aux_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_axi_clk = {
+	.halt_reg = 0x75008,
+	.clkr = {
+		.enable_reg = 0x75008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_axi_clk",
+			.parent_names = (const char *[]){ "ufs_axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_ahb_clk = {
+	.halt_reg = 0x7500c,
+	.clkr = {
+		.enable_reg = 0x7500c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_ahb_clk",
+			.parent_names = (const char *[]){ "config_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_fixed_factor ufs_tx_cfg_clk_src = {
+	.mult = 1,
+	.div = 16,
+	.hw.init = &(struct clk_init_data){
+		.name = "ufs_tx_cfg_clk_src",
+		.parent_names = (const char *[]){ "ufs_axi_clk_src" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_branch gcc_ufs_tx_cfg_clk = {
+	.halt_reg = 0x75010,
+	.clkr = {
+		.enable_reg = 0x75010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_tx_cfg_clk",
+			.parent_names = (const char *[]){ "ufs_tx_cfg_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_fixed_factor ufs_rx_cfg_clk_src = {
+	.mult = 1,
+	.div = 16,
+	.hw.init = &(struct clk_init_data){
+		.name = "ufs_rx_cfg_clk_src",
+		.parent_names = (const char *[]){ "ufs_axi_clk_src" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_branch gcc_ufs_rx_cfg_clk = {
+	.halt_reg = 0x75014,
+	.clkr = {
+		.enable_reg = 0x75014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_rx_cfg_clk",
+			.parent_names = (const char *[]){ "ufs_rx_cfg_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_tx_symbol_0_clk = {
+	.halt_reg = 0x75018,
+	.clkr = {
+		.enable_reg = 0x75018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_tx_symbol_0_clk",
+			.parent_names = (const char *[]){ "ufs_tx_symbol_0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_rx_symbol_0_clk = {
+	.halt_reg = 0x7501c,
+	.clkr = {
+		.enable_reg = 0x7501c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_rx_symbol_0_clk",
+			.parent_names = (const char *[]){ "ufs_rx_symbol_0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_rx_symbol_1_clk = {
+	.halt_reg = 0x75020,
+	.clkr = {
+		.enable_reg = 0x75020,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_rx_symbol_1_clk",
+			.parent_names = (const char *[]){ "ufs_rx_symbol_1_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_fixed_factor ufs_ice_core_postdiv_clk_src = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "ufs_ice_core_postdiv_clk_src",
+		.parent_names = (const char *[]){ "ufs_ice_core_clk_src" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_branch gcc_ufs_unipro_core_clk = {
+	.halt_reg = 0x7600c,
+	.clkr = {
+		.enable_reg = 0x7600c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_unipro_core_clk",
+			.parent_names = (const char *[]){ "ufs_ice_core_postdiv_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_ice_core_clk = {
+	.halt_reg = 0x76010,
+	.clkr = {
+		.enable_reg = 0x76010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_ice_core_clk",
+			.parent_names = (const char *[]){ "ufs_ice_core_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_sys_clk_core_clk = {
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x76030,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_sys_clk_core_clk",
+			.ops = &clk_branch2_ops,
+			.flags = CLK_IS_ROOT,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_tx_symbol_clk_core_clk = {
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x76034,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_tx_symbol_clk_core_clk",
+			.ops = &clk_branch2_ops,
+			.flags = CLK_IS_ROOT,
+		},
+	},
+};
+
+static struct clk_branch gcc_aggre0_snoc_axi_clk = {
+	.halt_reg = 0x81008,
+	.clkr = {
+		.enable_reg = 0x81008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_aggre0_snoc_axi_clk",
+			.parent_names = (const char *[]){ "system_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_aggre0_cnoc_ahb_clk = {
+	.halt_reg = 0x8100c,
+	.clkr = {
+		.enable_reg = 0x8100c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_aggre0_cnoc_ahb_clk",
+			.parent_names = (const char *[]){ "config_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_smmu_aggre0_axi_clk = {
+	.halt_reg = 0x81014,
+	.clkr = {
+		.enable_reg = 0x81014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_smmu_aggre0_axi_clk",
+			.parent_names = (const char *[]){ "system_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_smmu_aggre0_ahb_clk = {
+	.halt_reg = 0x81018,
+	.clkr = {
+		.enable_reg = 0x81018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_smmu_aggre0_ahb_clk",
+			.parent_names = (const char *[]){ "config_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_aggre1_pnoc_ahb_clk = {
+	.halt_reg = 0x82014,
+	.clkr = {
+		.enable_reg = 0x82014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_aggre1_pnoc_ahb_clk",
+			.parent_names = (const char *[]){ "periph_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_aggre2_ufs_axi_clk = {
+	.halt_reg = 0x83014,
+	.clkr = {
+		.enable_reg = 0x83014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_aggre2_ufs_axi_clk",
+			.parent_names = (const char *[]){ "ufs_axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_aggre2_usb3_axi_clk = {
+	.halt_reg = 0x83018,
+	.clkr = {
+		.enable_reg = 0x83018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_aggre2_usb3_axi_clk",
+			.parent_names = (const char *[]){ "usb30_master_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_qspi_ahb_clk = {
+	.halt_reg = 0x8b004,
+	.clkr = {
+		.enable_reg = 0x8b004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_qspi_ahb_clk",
+			.parent_names = (const char *[]){ "periph_noc_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_qspi_ser_clk = {
+	.halt_reg = 0x8b008,
+	.clkr = {
+		.enable_reg = 0x8b008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_qspi_ser_clk",
+			.parent_names = (const char *[]){ "qspi_ser_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb3_clkref_clk = {
+	.halt_reg = 0x8800C,
+	.clkr = {
+		.enable_reg = 0x8800C,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb3_clkref_clk",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_hdmi_clkref_clk = {
+	.halt_reg = 0x88000,
+	.clkr = {
+		.enable_reg = 0x88000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_hdmi_clkref_clk",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_clkref_clk = {
+	.halt_reg = 0x88008,
+	.clkr = {
+		.enable_reg = 0x88008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_clkref_clk",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_clkref_clk = {
+	.halt_reg = 0x88010,
+	.clkr = {
+		.enable_reg = 0x88010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_clkref_clk",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_rx2_usb2_clkref_clk = {
+	.halt_reg = 0x88014,
+	.clkr = {
+		.enable_reg = 0x88014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_rx2_usb2_clkref_clk",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_rx1_usb2_clkref_clk = {
+	.halt_reg = 0x88018,
+	.clkr = {
+		.enable_reg = 0x88018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_rx1_usb2_clkref_clk",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_hw *gcc_msm8996_hws[] = {
+	&xo.hw,
+	&gpll0_early_div.hw,
+	&ufs_tx_cfg_clk_src.hw,
+	&ufs_rx_cfg_clk_src.hw,
+	&ufs_ice_core_postdiv_clk_src.hw,
+};
+
+static struct clk_regmap *gcc_msm8996_clocks[] = {
+	[GPLL0_EARLY] = &gpll0_early.clkr,
+	[GPLL0] = &gpll0.clkr,
+	[GPLL4_EARLY] = &gpll4_early.clkr,
+	[GPLL4] = &gpll4.clkr,
+	[SYSTEM_NOC_CLK_SRC] = &system_noc_clk_src.clkr,
+	[CONFIG_NOC_CLK_SRC] = &config_noc_clk_src.clkr,
+	[PERIPH_NOC_CLK_SRC] = &periph_noc_clk_src.clkr,
+	[USB30_MASTER_CLK_SRC] = &usb30_master_clk_src.clkr,
+	[USB30_MOCK_UTMI_CLK_SRC] = &usb30_mock_utmi_clk_src.clkr,
+	[USB3_PHY_AUX_CLK_SRC] = &usb3_phy_aux_clk_src.clkr,
+	[USB20_MASTER_CLK_SRC] = &usb20_master_clk_src.clkr,
+	[USB20_MOCK_UTMI_CLK_SRC] = &usb20_mock_utmi_clk_src.clkr,
+	[SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr,
+	[SDCC1_ICE_CORE_CLK_SRC] = &sdcc1_ice_core_clk_src.clkr,
+	[SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr,
+	[SDCC3_APPS_CLK_SRC] = &sdcc3_apps_clk_src.clkr,
+	[SDCC4_APPS_CLK_SRC] = &sdcc4_apps_clk_src.clkr,
+	[BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
+	[BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
+	[BLSP1_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr,
+	[BLSP1_QUP2_SPI_APPS_CLK_SRC] = &blsp1_qup2_spi_apps_clk_src.clkr,
+	[BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr,
+	[BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr,
+	[BLSP1_QUP3_SPI_APPS_CLK_SRC] = &blsp1_qup3_spi_apps_clk_src.clkr,
+	[BLSP1_QUP3_I2C_APPS_CLK_SRC] = &blsp1_qup3_i2c_apps_clk_src.clkr,
+	[BLSP1_UART3_APPS_CLK_SRC] = &blsp1_uart3_apps_clk_src.clkr,
+	[BLSP1_QUP4_SPI_APPS_CLK_SRC] = &blsp1_qup4_spi_apps_clk_src.clkr,
+	[BLSP1_QUP4_I2C_APPS_CLK_SRC] = &blsp1_qup4_i2c_apps_clk_src.clkr,
+	[BLSP1_UART4_APPS_CLK_SRC] = &blsp1_uart4_apps_clk_src.clkr,
+	[BLSP1_QUP5_SPI_APPS_CLK_SRC] = &blsp1_qup5_spi_apps_clk_src.clkr,
+	[BLSP1_QUP5_I2C_APPS_CLK_SRC] = &blsp1_qup5_i2c_apps_clk_src.clkr,
+	[BLSP1_UART5_APPS_CLK_SRC] = &blsp1_uart5_apps_clk_src.clkr,
+	[BLSP1_QUP6_SPI_APPS_CLK_SRC] = &blsp1_qup6_spi_apps_clk_src.clkr,
+	[BLSP1_QUP6_I2C_APPS_CLK_SRC] = &blsp1_qup6_i2c_apps_clk_src.clkr,
+	[BLSP1_UART6_APPS_CLK_SRC] = &blsp1_uart6_apps_clk_src.clkr,
+	[BLSP2_QUP1_SPI_APPS_CLK_SRC] = &blsp2_qup1_spi_apps_clk_src.clkr,
+	[BLSP2_QUP1_I2C_APPS_CLK_SRC] = &blsp2_qup1_i2c_apps_clk_src.clkr,
+	[BLSP2_UART1_APPS_CLK_SRC] = &blsp2_uart1_apps_clk_src.clkr,
+	[BLSP2_QUP2_SPI_APPS_CLK_SRC] = &blsp2_qup2_spi_apps_clk_src.clkr,
+	[BLSP2_QUP2_I2C_APPS_CLK_SRC] = &blsp2_qup2_i2c_apps_clk_src.clkr,
+	[BLSP2_UART2_APPS_CLK_SRC] = &blsp2_uart2_apps_clk_src.clkr,
+	[BLSP2_QUP3_SPI_APPS_CLK_SRC] = &blsp2_qup3_spi_apps_clk_src.clkr,
+	[BLSP2_QUP3_I2C_APPS_CLK_SRC] = &blsp2_qup3_i2c_apps_clk_src.clkr,
+	[BLSP2_UART3_APPS_CLK_SRC] = &blsp2_uart3_apps_clk_src.clkr,
+	[BLSP2_QUP4_SPI_APPS_CLK_SRC] = &blsp2_qup4_spi_apps_clk_src.clkr,
+	[BLSP2_QUP4_I2C_APPS_CLK_SRC] = &blsp2_qup4_i2c_apps_clk_src.clkr,
+	[BLSP2_UART4_APPS_CLK_SRC] = &blsp2_uart4_apps_clk_src.clkr,
+	[BLSP2_QUP5_SPI_APPS_CLK_SRC] = &blsp2_qup5_spi_apps_clk_src.clkr,
+	[BLSP2_QUP5_I2C_APPS_CLK_SRC] = &blsp2_qup5_i2c_apps_clk_src.clkr,
+	[BLSP2_UART5_APPS_CLK_SRC] = &blsp2_uart5_apps_clk_src.clkr,
+	[BLSP2_QUP6_SPI_APPS_CLK_SRC] = &blsp2_qup6_spi_apps_clk_src.clkr,
+	[BLSP2_QUP6_I2C_APPS_CLK_SRC] = &blsp2_qup6_i2c_apps_clk_src.clkr,
+	[BLSP2_UART6_APPS_CLK_SRC] = &blsp2_uart6_apps_clk_src.clkr,
+	[PDM2_CLK_SRC] = &pdm2_clk_src.clkr,
+	[TSIF_REF_CLK_SRC] = &tsif_ref_clk_src.clkr,
+	[GCC_SLEEP_CLK_SRC] = &gcc_sleep_clk_src.clkr,
+	[HMSS_RBCPR_CLK_SRC] = &hmss_rbcpr_clk_src.clkr,
+	[HMSS_GPLL0_CLK_SRC] = &hmss_gpll0_clk_src.clkr,
+	[GP1_CLK_SRC] = &gp1_clk_src.clkr,
+	[GP2_CLK_SRC] = &gp2_clk_src.clkr,
+	[GP3_CLK_SRC] = &gp3_clk_src.clkr,
+	[PCIE_AUX_CLK_SRC] = &pcie_aux_clk_src.clkr,
+	[UFS_AXI_CLK_SRC] = &ufs_axi_clk_src.clkr,
+	[UFS_ICE_CORE_CLK_SRC] = &ufs_ice_core_clk_src.clkr,
+	[QSPI_SER_CLK_SRC] = &qspi_ser_clk_src.clkr,
+	[GCC_SYS_NOC_USB3_AXI_CLK] = &gcc_sys_noc_usb3_axi_clk.clkr,
+	[GCC_SYS_NOC_UFS_AXI_CLK] = &gcc_sys_noc_ufs_axi_clk.clkr,
+	[GCC_PERIPH_NOC_USB20_AHB_CLK] = &gcc_periph_noc_usb20_ahb_clk.clkr,
+	[GCC_MMSS_NOC_CFG_AHB_CLK] = &gcc_mmss_noc_cfg_ahb_clk.clkr,
+	[GCC_MMSS_BIMC_GFX_CLK] = &gcc_mmss_bimc_gfx_clk.clkr,
+	[GCC_USB30_MASTER_CLK] = &gcc_usb30_master_clk.clkr,
+	[GCC_USB30_SLEEP_CLK] = &gcc_usb30_sleep_clk.clkr,
+	[GCC_USB30_MOCK_UTMI_CLK] = &gcc_usb30_mock_utmi_clk.clkr,
+	[GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr,
+	[GCC_USB3_PHY_PIPE_CLK] = &gcc_usb3_phy_pipe_clk.clkr,
+	[GCC_USB20_MASTER_CLK] = &gcc_usb20_master_clk.clkr,
+	[GCC_USB20_SLEEP_CLK] = &gcc_usb20_sleep_clk.clkr,
+	[GCC_USB20_MOCK_UTMI_CLK] = &gcc_usb20_mock_utmi_clk.clkr,
+	[GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr,
+	[GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
+	[GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
+	[GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr,
+	[GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
+	[GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
+	[GCC_SDCC3_APPS_CLK] = &gcc_sdcc3_apps_clk.clkr,
+	[GCC_SDCC3_AHB_CLK] = &gcc_sdcc3_ahb_clk.clkr,
+	[GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr,
+	[GCC_SDCC4_AHB_CLK] = &gcc_sdcc4_ahb_clk.clkr,
+	[GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr,
+	[GCC_BLSP1_SLEEP_CLK] = &gcc_blsp1_sleep_clk.clkr,
+	[GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr,
+	[GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr,
+	[GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr,
+	[GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr,
+	[GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr,
+	[GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr,
+	[GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr,
+	[GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr,
+	[GCC_BLSP1_UART3_APPS_CLK] = &gcc_blsp1_uart3_apps_clk.clkr,
+	[GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr,
+	[GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr,
+	[GCC_BLSP1_UART4_APPS_CLK] = &gcc_blsp1_uart4_apps_clk.clkr,
+	[GCC_BLSP1_QUP5_SPI_APPS_CLK] = &gcc_blsp1_qup5_spi_apps_clk.clkr,
+	[GCC_BLSP1_QUP5_I2C_APPS_CLK] = &gcc_blsp1_qup5_i2c_apps_clk.clkr,
+	[GCC_BLSP1_UART5_APPS_CLK] = &gcc_blsp1_uart5_apps_clk.clkr,
+	[GCC_BLSP1_QUP6_SPI_APPS_CLK] = &gcc_blsp1_qup6_spi_apps_clk.clkr,
+	[GCC_BLSP1_QUP6_I2C_APPS_CLK] = &gcc_blsp1_qup6_i2c_apps_clk.clkr,
+	[GCC_BLSP1_UART6_APPS_CLK] = &gcc_blsp1_uart6_apps_clk.clkr,
+	[GCC_BLSP2_AHB_CLK] = &gcc_blsp2_ahb_clk.clkr,
+	[GCC_BLSP2_SLEEP_CLK] = &gcc_blsp2_sleep_clk.clkr,
+	[GCC_BLSP2_QUP1_SPI_APPS_CLK] = &gcc_blsp2_qup1_spi_apps_clk.clkr,
+	[GCC_BLSP2_QUP1_I2C_APPS_CLK] = &gcc_blsp2_qup1_i2c_apps_clk.clkr,
+	[GCC_BLSP2_UART1_APPS_CLK] = &gcc_blsp2_uart1_apps_clk.clkr,
+	[GCC_BLSP2_QUP2_SPI_APPS_CLK] = &gcc_blsp2_qup2_spi_apps_clk.clkr,
+	[GCC_BLSP2_QUP2_I2C_APPS_CLK] = &gcc_blsp2_qup2_i2c_apps_clk.clkr,
+	[GCC_BLSP2_UART2_APPS_CLK] = &gcc_blsp2_uart2_apps_clk.clkr,
+	[GCC_BLSP2_QUP3_SPI_APPS_CLK] = &gcc_blsp2_qup3_spi_apps_clk.clkr,
+	[GCC_BLSP2_QUP3_I2C_APPS_CLK] = &gcc_blsp2_qup3_i2c_apps_clk.clkr,
+	[GCC_BLSP2_UART3_APPS_CLK] = &gcc_blsp2_uart3_apps_clk.clkr,
+	[GCC_BLSP2_QUP4_SPI_APPS_CLK] = &gcc_blsp2_qup4_spi_apps_clk.clkr,
+	[GCC_BLSP2_QUP4_I2C_APPS_CLK] = &gcc_blsp2_qup4_i2c_apps_clk.clkr,
+	[GCC_BLSP2_UART4_APPS_CLK] = &gcc_blsp2_uart4_apps_clk.clkr,
+	[GCC_BLSP2_QUP5_SPI_APPS_CLK] = &gcc_blsp2_qup5_spi_apps_clk.clkr,
+	[GCC_BLSP2_QUP5_I2C_APPS_CLK] = &gcc_blsp2_qup5_i2c_apps_clk.clkr,
+	[GCC_BLSP2_UART5_APPS_CLK] = &gcc_blsp2_uart5_apps_clk.clkr,
+	[GCC_BLSP2_QUP6_SPI_APPS_CLK] = &gcc_blsp2_qup6_spi_apps_clk.clkr,
+	[GCC_BLSP2_QUP6_I2C_APPS_CLK] = &gcc_blsp2_qup6_i2c_apps_clk.clkr,
+	[GCC_BLSP2_UART6_APPS_CLK] = &gcc_blsp2_uart6_apps_clk.clkr,
+	[GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+	[GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+	[GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr,
+	[GCC_TSIF_AHB_CLK] = &gcc_tsif_ahb_clk.clkr,
+	[GCC_TSIF_REF_CLK] = &gcc_tsif_ref_clk.clkr,
+	[GCC_TSIF_INACTIVITY_TIMERS_CLK] = &gcc_tsif_inactivity_timers_clk.clkr,
+	[GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+	[GCC_BIMC_GFX_CLK] = &gcc_bimc_gfx_clk.clkr,
+	[GCC_HMSS_RBCPR_CLK] = &gcc_hmss_rbcpr_clk.clkr,
+	[GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+	[GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+	[GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+	[GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr,
+	[GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr,
+	[GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr,
+	[GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr,
+	[GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr,
+	[GCC_PCIE_1_SLV_AXI_CLK] = &gcc_pcie_1_slv_axi_clk.clkr,
+	[GCC_PCIE_1_MSTR_AXI_CLK] = &gcc_pcie_1_mstr_axi_clk.clkr,
+	[GCC_PCIE_1_CFG_AHB_CLK] = &gcc_pcie_1_cfg_ahb_clk.clkr,
+	[GCC_PCIE_1_AUX_CLK] = &gcc_pcie_1_aux_clk.clkr,
+	[GCC_PCIE_1_PIPE_CLK] = &gcc_pcie_1_pipe_clk.clkr,
+	[GCC_PCIE_2_SLV_AXI_CLK] = &gcc_pcie_2_slv_axi_clk.clkr,
+	[GCC_PCIE_2_MSTR_AXI_CLK] = &gcc_pcie_2_mstr_axi_clk.clkr,
+	[GCC_PCIE_2_CFG_AHB_CLK] = &gcc_pcie_2_cfg_ahb_clk.clkr,
+	[GCC_PCIE_2_AUX_CLK] = &gcc_pcie_2_aux_clk.clkr,
+	[GCC_PCIE_2_PIPE_CLK] = &gcc_pcie_2_pipe_clk.clkr,
+	[GCC_PCIE_PHY_CFG_AHB_CLK] = &gcc_pcie_phy_cfg_ahb_clk.clkr,
+	[GCC_PCIE_PHY_AUX_CLK] = &gcc_pcie_phy_aux_clk.clkr,
+	[GCC_UFS_AXI_CLK] = &gcc_ufs_axi_clk.clkr,
+	[GCC_UFS_AHB_CLK] = &gcc_ufs_ahb_clk.clkr,
+	[GCC_UFS_TX_CFG_CLK] = &gcc_ufs_tx_cfg_clk.clkr,
+	[GCC_UFS_RX_CFG_CLK] = &gcc_ufs_rx_cfg_clk.clkr,
+	[GCC_UFS_TX_SYMBOL_0_CLK] = &gcc_ufs_tx_symbol_0_clk.clkr,
+	[GCC_UFS_RX_SYMBOL_0_CLK] = &gcc_ufs_rx_symbol_0_clk.clkr,
+	[GCC_UFS_RX_SYMBOL_1_CLK] = &gcc_ufs_rx_symbol_1_clk.clkr,
+	[GCC_UFS_UNIPRO_CORE_CLK] = &gcc_ufs_unipro_core_clk.clkr,
+	[GCC_UFS_ICE_CORE_CLK] = &gcc_ufs_ice_core_clk.clkr,
+	[GCC_UFS_SYS_CLK_CORE_CLK] = &gcc_ufs_sys_clk_core_clk.clkr,
+	[GCC_UFS_TX_SYMBOL_CLK_CORE_CLK] = &gcc_ufs_tx_symbol_clk_core_clk.clkr,
+	[GCC_AGGRE0_SNOC_AXI_CLK] = &gcc_aggre0_snoc_axi_clk.clkr,
+	[GCC_AGGRE0_CNOC_AHB_CLK] = &gcc_aggre0_cnoc_ahb_clk.clkr,
+	[GCC_SMMU_AGGRE0_AXI_CLK] = &gcc_smmu_aggre0_axi_clk.clkr,
+	[GCC_SMMU_AGGRE0_AHB_CLK] = &gcc_smmu_aggre0_ahb_clk.clkr,
+	[GCC_AGGRE1_PNOC_AHB_CLK] = &gcc_aggre1_pnoc_ahb_clk.clkr,
+	[GCC_AGGRE2_UFS_AXI_CLK] = &gcc_aggre2_ufs_axi_clk.clkr,
+	[GCC_AGGRE2_USB3_AXI_CLK] = &gcc_aggre2_usb3_axi_clk.clkr,
+	[GCC_QSPI_AHB_CLK] = &gcc_qspi_ahb_clk.clkr,
+	[GCC_QSPI_SER_CLK] = &gcc_qspi_ser_clk.clkr,
+	[GCC_USB3_CLKREF_CLK] = &gcc_usb3_clkref_clk.clkr,
+	[GCC_HDMI_CLKREF_CLK] = &gcc_hdmi_clkref_clk.clkr,
+	[GCC_UFS_CLKREF_CLK] = &gcc_ufs_clkref_clk.clkr,
+	[GCC_PCIE_CLKREF_CLK] = &gcc_pcie_clkref_clk.clkr,
+	[GCC_RX2_USB2_CLKREF_CLK] = &gcc_rx2_usb2_clkref_clk.clkr,
+	[GCC_RX1_USB2_CLKREF_CLK] = &gcc_rx1_usb2_clkref_clk.clkr,
+};
+
+static const struct qcom_reset_map gcc_msm8996_resets[] = {
+	[GCC_SYSTEM_NOC_BCR] = { 0x4000 },
+	[GCC_CONFIG_NOC_BCR] = { 0x5000 },
+	[GCC_PERIPH_NOC_BCR] = { 0x6000 },
+	[GCC_IMEM_BCR] = { 0x8000 },
+	[GCC_MMSS_BCR] = { 0x9000 },
+	[GCC_PIMEM_BCR] = { 0x0a000 },
+	[GCC_QDSS_BCR] = { 0x0c000 },
+	[GCC_USB_30_BCR] = { 0x0f000 },
+	[GCC_USB_20_BCR] = { 0x12000 },
+	[GCC_QUSB2PHY_PRIM_BCR] = { 0x12038 },
+	[GCC_QUSB2PHY_SEC_BCR] = { 0x1203c },
+	[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
+	[GCC_SDCC1_BCR] = { 0x13000 },
+	[GCC_SDCC2_BCR] = { 0x14000 },
+	[GCC_SDCC3_BCR] = { 0x15000 },
+	[GCC_SDCC4_BCR] = { 0x16000 },
+	[GCC_BLSP1_BCR] = { 0x17000 },
+	[GCC_BLSP1_QUP1_BCR] = { 0x19000 },
+	[GCC_BLSP1_UART1_BCR] = { 0x1a000 },
+	[GCC_BLSP1_QUP2_BCR] = { 0x1b000 },
+	[GCC_BLSP1_UART2_BCR] = { 0x1c000 },
+	[GCC_BLSP1_QUP3_BCR] = { 0x1d000 },
+	[GCC_BLSP1_UART3_BCR] = { 0x1e000 },
+	[GCC_BLSP1_QUP4_BCR] = { 0x1f000 },
+	[GCC_BLSP1_UART4_BCR] = { 0x20000 },
+	[GCC_BLSP1_QUP5_BCR] = { 0x21000 },
+	[GCC_BLSP1_UART5_BCR] = { 0x22000 },
+	[GCC_BLSP1_QUP6_BCR] = { 0x23000 },
+	[GCC_BLSP1_UART6_BCR] = { 0x24000 },
+	[GCC_BLSP2_BCR] = { 0x25000 },
+	[GCC_BLSP2_QUP1_BCR] = { 0x26000 },
+	[GCC_BLSP2_UART1_BCR] = { 0x27000 },
+	[GCC_BLSP2_QUP2_BCR] = { 0x28000 },
+	[GCC_BLSP2_UART2_BCR] = { 0x29000 },
+	[GCC_BLSP2_QUP3_BCR] = { 0x2a000 },
+	[GCC_BLSP2_UART3_BCR] = { 0x2b000 },
+	[GCC_BLSP2_QUP4_BCR] = { 0x2c000 },
+	[GCC_BLSP2_UART4_BCR] = { 0x2d000 },
+	[GCC_BLSP2_QUP5_BCR] = { 0x2e000 },
+	[GCC_BLSP2_UART5_BCR] = { 0x2f000 },
+	[GCC_BLSP2_QUP6_BCR] = { 0x30000 },
+	[GCC_BLSP2_UART6_BCR] = { 0x31000 },
+	[GCC_PDM_BCR] = { 0x33000 },
+	[GCC_PRNG_BCR] = { 0x34000 },
+	[GCC_TSIF_BCR] = { 0x36000 },
+	[GCC_TCSR_BCR] = { 0x37000 },
+	[GCC_BOOT_ROM_BCR] = { 0x38000 },
+	[GCC_MSG_RAM_BCR] = { 0x39000 },
+	[GCC_TLMM_BCR] = { 0x3a000 },
+	[GCC_MPM_BCR] = { 0x3b000 },
+	[GCC_SEC_CTRL_BCR] = { 0x3d000 },
+	[GCC_SPMI_BCR] = { 0x3f000 },
+	[GCC_SPDM_BCR] = { 0x40000 },
+	[GCC_CE1_BCR] = { 0x41000 },
+	[GCC_BIMC_BCR] = { 0x44000 },
+	[GCC_SNOC_BUS_TIMEOUT0_BCR] = { 0x49000 },
+	[GCC_SNOC_BUS_TIMEOUT2_BCR] = { 0x49008 },
+	[GCC_SNOC_BUS_TIMEOUT1_BCR] = { 0x49010 },
+	[GCC_SNOC_BUS_TIMEOUT3_BCR] = { 0x49018 },
+	[GCC_SNOC_BUS_TIMEOUT_EXTREF_BCR] = { 0x49020 },
+	[GCC_PNOC_BUS_TIMEOUT0_BCR] = { 0x4a000 },
+	[GCC_PNOC_BUS_TIMEOUT1_BCR] = { 0x4a008 },
+	[GCC_PNOC_BUS_TIMEOUT2_BCR] = { 0x4a010 },
+	[GCC_PNOC_BUS_TIMEOUT3_BCR] = { 0x4a018 },
+	[GCC_PNOC_BUS_TIMEOUT4_BCR] = { 0x4a020 },
+	[GCC_CNOC_BUS_TIMEOUT0_BCR] = { 0x4b000 },
+	[GCC_CNOC_BUS_TIMEOUT1_BCR] = { 0x4b008 },
+	[GCC_CNOC_BUS_TIMEOUT2_BCR] = { 0x4b010 },
+	[GCC_CNOC_BUS_TIMEOUT3_BCR] = { 0x4b018 },
+	[GCC_CNOC_BUS_TIMEOUT4_BCR] = { 0x4b020 },
+	[GCC_CNOC_BUS_TIMEOUT5_BCR] = { 0x4b028 },
+	[GCC_CNOC_BUS_TIMEOUT6_BCR] = { 0x4b030 },
+	[GCC_CNOC_BUS_TIMEOUT7_BCR] = { 0x4b038 },
+	[GCC_CNOC_BUS_TIMEOUT8_BCR] = { 0x80000 },
+	[GCC_CNOC_BUS_TIMEOUT9_BCR] = { 0x80008 },
+	[GCC_CNOC_BUS_TIMEOUT_EXTREF_BCR] = { 0x80010 },
+	[GCC_APB2JTAG_BCR] = { 0x4c000 },
+	[GCC_RBCPR_CX_BCR] = { 0x4e000 },
+	[GCC_RBCPR_MX_BCR] = { 0x4f000 },
+	[GCC_PCIE_0_BCR] = { 0x6b000 },
+	[GCC_PCIE_0_PHY_BCR] = { 0x6c01c },
+	[GCC_PCIE_1_BCR] = { 0x6d000 },
+	[GCC_PCIE_1_PHY_BCR] = { 0x6d038 },
+	[GCC_PCIE_2_BCR] = { 0x6e000 },
+	[GCC_PCIE_2_PHY_BCR] = { 0x6e038 },
+	[GCC_PCIE_PHY_BCR] = { 0x6f000 },
+	[GCC_DCD_BCR] = { 0x70000 },
+	[GCC_OBT_ODT_BCR] = { 0x73000 },
+	[GCC_UFS_BCR] = { 0x75000 },
+	[GCC_SSC_BCR] = { 0x63000 },
+	[GCC_VS_BCR] = { 0x7a000 },
+	[GCC_AGGRE0_NOC_BCR] = { 0x81000 },
+	[GCC_AGGRE1_NOC_BCR] = { 0x82000 },
+	[GCC_AGGRE2_NOC_BCR] = { 0x83000 },
+	[GCC_DCC_BCR] = { 0x84000 },
+	[GCC_IPA_BCR] = { 0x89000 },
+	[GCC_QSPI_BCR] = { 0x8b000 },
+	[GCC_SKL_BCR] = { 0x8c000 },
+	[GCC_MSMPU_BCR] = { 0x8d000 },
+	[GCC_MSS_Q6_BCR] = { 0x8e000 },
+	[GCC_QREFS_VBG_CAL_BCR] = { 0x88020 },
+};
+
+static const struct regmap_config gcc_msm8996_regmap_config = {
+	.reg_bits	= 32,
+	.reg_stride	= 4,
+	.val_bits	= 32,
+	.max_register	= 0x8f010,
+	.fast_io	= true,
+};
+
+static const struct qcom_cc_desc gcc_msm8996_desc = {
+	.config = &gcc_msm8996_regmap_config,
+	.clks = gcc_msm8996_clocks,
+	.num_clks = ARRAY_SIZE(gcc_msm8996_clocks),
+	.resets = gcc_msm8996_resets,
+	.num_resets = ARRAY_SIZE(gcc_msm8996_resets),
+};
+
+static const struct of_device_id gcc_msm8996_match_table[] = {
+	{ .compatible = "qcom,gcc-msm8996" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, gcc_msm8996_match_table);
+
+static int gcc_msm8996_probe(struct platform_device *pdev)
+{
+	struct clk *clk;
+	struct device *dev = &pdev->dev;
+	int i;
+	struct regmap *regmap;
+
+	regmap = qcom_cc_map(pdev, &gcc_msm8996_desc);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	/*
+	 * Set the HMSS_AHB_CLK_SLEEP_ENA bit to allow the hmss_ahb_clk to be
+	 * turned off by hardware during certain apps low power modes.
+	 */
+	regmap_update_bits(regmap, 0x52008, BIT(21), BIT(21));
+
+	for (i = 0; i < ARRAY_SIZE(gcc_msm8996_hws); i++) {
+		clk = devm_clk_register(dev, gcc_msm8996_hws[i]);
+		if (IS_ERR(clk))
+			return PTR_ERR(clk);
+	}
+
+	return qcom_cc_really_probe(pdev, &gcc_msm8996_desc, regmap);
+}
+
+static struct platform_driver gcc_msm8996_driver = {
+	.probe		= gcc_msm8996_probe,
+	.driver		= {
+		.name	= "gcc-msm8996",
+		.of_match_table = gcc_msm8996_match_table,
+	},
+};
+
+static int __init gcc_msm8996_init(void)
+{
+	return platform_driver_register(&gcc_msm8996_driver);
+}
+core_initcall(gcc_msm8996_init);
+
+static void __exit gcc_msm8996_exit(void)
+{
+	platform_driver_unregister(&gcc_msm8996_driver);
+}
+module_exit(gcc_msm8996_exit);
+
+MODULE_DESCRIPTION("QCOM GCC MSM8996 Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:gcc-msm8996");
diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c
index db3998e..62e79fa 100644
--- a/drivers/clk/qcom/lcc-ipq806x.c
+++ b/drivers/clk/qcom/lcc-ipq806x.c
@@ -419,6 +419,7 @@
 	.val_bits	= 32,
 	.max_register	= 0xfc,
 	.fast_io	= true,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc lcc_ipq806x_desc = {
diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c
index 4fcf9d1..bf95bb0 100644
--- a/drivers/clk/qcom/lcc-msm8960.c
+++ b/drivers/clk/qcom/lcc-msm8960.c
@@ -524,6 +524,7 @@
 	.val_bits	= 32,
 	.max_register	= 0xfc,
 	.fast_io	= true,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc lcc_msm8960_desc = {
diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c
index 30777f9..1e703fd 100644
--- a/drivers/clk/qcom/mmcc-apq8084.c
+++ b/drivers/clk/qcom/mmcc-apq8084.c
@@ -3368,6 +3368,7 @@
 	.val_bits	= 32,
 	.max_register	= 0x5104,
 	.fast_io	= true,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc mmcc_apq8084_desc = {
diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c
index 00e3619..d73a048 100644
--- a/drivers/clk/qcom/mmcc-msm8960.c
+++ b/drivers/clk/qcom/mmcc-msm8960.c
@@ -3029,6 +3029,7 @@
 	.val_bits	= 32,
 	.max_register	= 0x334,
 	.fast_io	= true,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct regmap_config mmcc_apq8064_regmap_config = {
@@ -3037,6 +3038,7 @@
 	.val_bits	= 32,
 	.max_register	= 0x350,
 	.fast_io	= true,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc mmcc_msm8960_desc = {
diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c
index 9d790bc..bbe28ed 100644
--- a/drivers/clk/qcom/mmcc-msm8974.c
+++ b/drivers/clk/qcom/mmcc-msm8974.c
@@ -2594,6 +2594,7 @@
 	.val_bits	= 32,
 	.max_register	= 0x5104,
 	.fast_io	= true,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc mmcc_msm8974_desc = {
diff --git a/drivers/clk/qcom/mmcc-msm8996.c b/drivers/clk/qcom/mmcc-msm8996.c
new file mode 100644
index 0000000..064f3ea
--- /dev/null
+++ b/drivers/clk/qcom/mmcc-msm8996.c
@@ -0,0 +1,3217 @@
+/*x
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+#include <linux/clk.h>
+
+#include <dt-bindings/clock/qcom,mmcc-msm8996.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-alpha-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "reset.h"
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+
+enum {
+	P_XO,
+	P_MMPLL0,
+	P_GPLL0,
+	P_GPLL0_DIV,
+	P_MMPLL1,
+	P_MMPLL9,
+	P_MMPLL2,
+	P_MMPLL8,
+	P_MMPLL3,
+	P_DSI0PLL,
+	P_DSI1PLL,
+	P_MMPLL5,
+	P_HDMIPLL,
+	P_DSI0PLL_BYTE,
+	P_DSI1PLL_BYTE,
+	P_MMPLL4,
+};
+
+static const struct parent_map mmss_xo_hdmi_map[] = {
+	{ P_XO, 0 },
+	{ P_HDMIPLL, 1 }
+};
+
+static const char * const mmss_xo_hdmi[] = {
+	"xo",
+	"hdmipll"
+};
+
+static const struct parent_map mmss_xo_dsi0pll_dsi1pll_map[] = {
+	{ P_XO, 0 },
+	{ P_DSI0PLL, 1 },
+	{ P_DSI1PLL, 2 }
+};
+
+static const char * const mmss_xo_dsi0pll_dsi1pll[] = {
+	"xo",
+	"dsi0pll",
+	"dsi1pll"
+};
+
+static const struct parent_map mmss_xo_gpll0_gpll0_div_map[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 5 },
+	{ P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_gpll0_gpll0_div[] = {
+	"xo",
+	"gpll0",
+	"gpll0_div"
+};
+
+static const struct parent_map mmss_xo_dsibyte_map[] = {
+	{ P_XO, 0 },
+	{ P_DSI0PLL_BYTE, 1 },
+	{ P_DSI1PLL_BYTE, 2 }
+};
+
+static const char * const mmss_xo_dsibyte[] = {
+	"xo",
+	"dsi0pllbyte",
+	"dsi1pllbyte"
+};
+
+static const struct parent_map mmss_xo_mmpll0_gpll0_gpll0_div_map[] = {
+	{ P_XO, 0 },
+	{ P_MMPLL0, 1 },
+	{ P_GPLL0, 5 },
+	{ P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_mmpll0_gpll0_gpll0_div[] = {
+	"xo",
+	"mmpll0",
+	"gpll0",
+	"gpll0_div"
+};
+
+static const struct parent_map mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div_map[] = {
+	{ P_XO, 0 },
+	{ P_MMPLL0, 1 },
+	{ P_MMPLL1, 2 },
+	{ P_GPLL0, 5 },
+	{ P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div[] = {
+	"xo",
+	"mmpll0",
+	"mmpll1",
+	"gpll0",
+	"gpll0_div"
+};
+
+static const struct parent_map mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div_map[] = {
+	{ P_XO, 0 },
+	{ P_MMPLL0, 1 },
+	{ P_MMPLL3, 3 },
+	{ P_GPLL0, 5 },
+	{ P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div[] = {
+	"xo",
+	"mmpll0",
+	"mmpll3",
+	"gpll0",
+	"gpll0_div"
+};
+
+static const struct parent_map mmss_xo_mmpll0_mmpll5_gpll0_gpll0_div_map[] = {
+	{ P_XO, 0 },
+	{ P_MMPLL0, 1 },
+	{ P_MMPLL5, 2 },
+	{ P_GPLL0, 5 },
+	{ P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_mmpll0_mmpll5_gpll0_gpll0_div[] = {
+	"xo",
+	"mmpll0",
+	"mmpll5",
+	"gpll0",
+	"gpll0_div"
+};
+
+static const struct parent_map mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map[] = {
+	{ P_XO, 0 },
+	{ P_MMPLL0, 1 },
+	{ P_MMPLL4, 3 },
+	{ P_GPLL0, 5 },
+	{ P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div[] = {
+	"xo",
+	"mmpll0",
+	"mmpll4",
+	"gpll0",
+	"gpll0_div"
+};
+
+static const struct parent_map mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0_map[] = {
+	{ P_XO, 0 },
+	{ P_MMPLL0, 1 },
+	{ P_MMPLL9, 2 },
+	{ P_MMPLL2, 3 },
+	{ P_MMPLL8, 4 },
+	{ P_GPLL0, 5 }
+};
+
+static const char * const mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0[] = {
+	"xo",
+	"mmpll0",
+	"mmpll9",
+	"mmpll2",
+	"mmpll8",
+	"gpll0"
+};
+
+static const struct parent_map mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0_gpll0_div_map[] = {
+	{ P_XO, 0 },
+	{ P_MMPLL0, 1 },
+	{ P_MMPLL9, 2 },
+	{ P_MMPLL2, 3 },
+	{ P_MMPLL8, 4 },
+	{ P_GPLL0, 5 },
+	{ P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0_gpll0_div[] = {
+	"xo",
+	"mmpll0",
+	"mmpll9",
+	"mmpll2",
+	"mmpll8",
+	"gpll0",
+	"gpll0_div"
+};
+
+static const struct parent_map mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map[] = {
+	{ P_XO, 0 },
+	{ P_MMPLL0, 1 },
+	{ P_MMPLL1, 2 },
+	{ P_MMPLL4, 3 },
+	{ P_MMPLL3, 4 },
+	{ P_GPLL0, 5 },
+	{ P_GPLL0_DIV, 6 }
+};
+
+static const char * const mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div[] = {
+	"xo",
+	"mmpll0",
+	"mmpll1",
+	"mmpll4",
+	"mmpll3",
+	"gpll0",
+	"gpll0_div"
+};
+
+static struct clk_fixed_factor gpll0_div = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "gpll0_div",
+		.parent_names = (const char *[]){ "gpll0" },
+		.num_parents = 1,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct pll_vco mmpll_p_vco[] = {
+	{ 250000000, 500000000, 3 },
+	{ 500000000, 1000000000, 2 },
+	{ 1000000000, 1500000000, 1 },
+	{ 1500000000, 2000000000, 0 },
+};
+
+static struct pll_vco mmpll_gfx_vco[] = {
+	{ 400000000, 1000000000, 2 },
+	{ 1000000000, 1500000000, 1 },
+	{ 1500000000, 2000000000, 0 },
+};
+
+static struct pll_vco mmpll_t_vco[] = {
+	{ 500000000, 1500000000, 0 },
+};
+
+static struct clk_alpha_pll mmpll0_early = {
+	.offset = 0x0,
+	.vco_table = mmpll_p_vco,
+	.num_vco = ARRAY_SIZE(mmpll_p_vco),
+	.clkr = {
+		.enable_reg = 0x100,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmpll0_early",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_ops,
+		},
+	},
+};
+
+static struct clk_alpha_pll_postdiv mmpll0 = {
+	.offset = 0x0,
+	.width = 4,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mmpll0",
+		.parent_names = (const char *[]){ "mmpll0_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_alpha_pll mmpll1_early = {
+	.offset = 0x30,
+	.vco_table = mmpll_p_vco,
+	.num_vco = ARRAY_SIZE(mmpll_p_vco),
+	.clkr = {
+		.enable_reg = 0x100,
+		.enable_mask = BIT(1),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmpll1_early",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_ops,
+		}
+	},
+};
+
+static struct clk_alpha_pll_postdiv mmpll1 = {
+	.offset = 0x30,
+	.width = 4,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mmpll1",
+		.parent_names = (const char *[]){ "mmpll1_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_alpha_pll mmpll2_early = {
+	.offset = 0x4100,
+	.vco_table = mmpll_gfx_vco,
+	.num_vco = ARRAY_SIZE(mmpll_gfx_vco),
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mmpll2_early",
+		.parent_names = (const char *[]){ "xo" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_ops,
+	},
+};
+
+static struct clk_alpha_pll_postdiv mmpll2 = {
+	.offset = 0x4100,
+	.width = 4,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mmpll2",
+		.parent_names = (const char *[]){ "mmpll2_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_alpha_pll mmpll3_early = {
+	.offset = 0x60,
+	.vco_table = mmpll_p_vco,
+	.num_vco = ARRAY_SIZE(mmpll_p_vco),
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mmpll3_early",
+		.parent_names = (const char *[]){ "xo" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_ops,
+	},
+};
+
+static struct clk_alpha_pll_postdiv mmpll3 = {
+	.offset = 0x60,
+	.width = 4,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mmpll3",
+		.parent_names = (const char *[]){ "mmpll3_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_alpha_pll mmpll4_early = {
+	.offset = 0x90,
+	.vco_table = mmpll_t_vco,
+	.num_vco = ARRAY_SIZE(mmpll_t_vco),
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mmpll4_early",
+		.parent_names = (const char *[]){ "xo" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_ops,
+	},
+};
+
+static struct clk_alpha_pll_postdiv mmpll4 = {
+	.offset = 0x90,
+	.width = 2,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mmpll4",
+		.parent_names = (const char *[]){ "mmpll4_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_alpha_pll mmpll5_early = {
+	.offset = 0xc0,
+	.vco_table = mmpll_p_vco,
+	.num_vco = ARRAY_SIZE(mmpll_p_vco),
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mmpll5_early",
+		.parent_names = (const char *[]){ "xo" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_ops,
+	},
+};
+
+static struct clk_alpha_pll_postdiv mmpll5 = {
+	.offset = 0xc0,
+	.width = 4,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mmpll5",
+		.parent_names = (const char *[]){ "mmpll5_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_alpha_pll mmpll8_early = {
+	.offset = 0x4130,
+	.vco_table = mmpll_gfx_vco,
+	.num_vco = ARRAY_SIZE(mmpll_gfx_vco),
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mmpll8_early",
+		.parent_names = (const char *[]){ "xo" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_ops,
+	},
+};
+
+static struct clk_alpha_pll_postdiv mmpll8 = {
+	.offset = 0x4130,
+	.width = 4,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mmpll8",
+		.parent_names = (const char *[]){ "mmpll8_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_alpha_pll mmpll9_early = {
+	.offset = 0x4200,
+	.vco_table = mmpll_t_vco,
+	.num_vco = ARRAY_SIZE(mmpll_t_vco),
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mmpll9_early",
+		.parent_names = (const char *[]){ "xo" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_ops,
+	},
+};
+
+static struct clk_alpha_pll_postdiv mmpll9 = {
+	.offset = 0x4200,
+	.width = 2,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mmpll9",
+		.parent_names = (const char *[]){ "mmpll9_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct freq_tbl ftbl_ahb_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(40000000, P_GPLL0_DIV, 7.5, 0, 0),
+	F(80000000, P_MMPLL0, 10, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ahb_clk_src = {
+	.cmd_rcgr = 0x5000,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_ahb_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "ahb_clk_src",
+		.parent_names = mmss_xo_mmpll0_gpll0_gpll0_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_axi_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(75000000, P_GPLL0_DIV, 4, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(171430000, P_GPLL0, 3.5, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(320000000, P_MMPLL0, 2.5, 0, 0),
+	F(400000000, P_MMPLL0, 2, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 axi_clk_src = {
+	.cmd_rcgr = 0x5040,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_axi_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "axi_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div,
+		.num_parents = 5,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 maxi_clk_src = {
+	.cmd_rcgr = 0x5090,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_axi_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "maxi_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div,
+		.num_parents = 5,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 gfx3d_clk_src = {
+	.cmd_rcgr = 0x4000,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0_map,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gfx3d_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0,
+		.num_parents = 6,
+		.ops = &clk_gfx3d_ops,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct freq_tbl ftbl_rbbmtimer_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 rbbmtimer_clk_src = {
+	.cmd_rcgr = 0x4090,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_rbbmtimer_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "rbbmtimer_clk_src",
+		.parent_names = mmss_xo_mmpll0_gpll0_gpll0_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 isense_clk_src = {
+	.cmd_rcgr = 0x4010,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0_gpll0_div_map,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "isense_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_rbcpr_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(50000000, P_GPLL0, 12, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 rbcpr_clk_src = {
+	.cmd_rcgr = 0x4060,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_rbcpr_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "rbcpr_clk_src",
+		.parent_names = mmss_xo_mmpll0_gpll0_gpll0_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_video_core_clk_src[] = {
+	F(75000000, P_GPLL0_DIV, 4, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(346666667, P_MMPLL3, 3, 0, 0),
+	F(520000000, P_MMPLL3, 2, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 video_core_clk_src = {
+	.cmd_rcgr = 0x1000,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_video_core_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "video_core_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div,
+		.num_parents = 5,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 video_subcore0_clk_src = {
+	.cmd_rcgr = 0x1060,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_video_core_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "video_subcore0_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div,
+		.num_parents = 5,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 video_subcore1_clk_src = {
+	.cmd_rcgr = 0x1080,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_video_core_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "video_subcore1_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div,
+		.num_parents = 5,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 pclk0_clk_src = {
+	.cmd_rcgr = 0x2000,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = mmss_xo_dsi0pll_dsi1pll_map,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "pclk0_clk_src",
+		.parent_names = mmss_xo_dsi0pll_dsi1pll,
+		.num_parents = 3,
+		.ops = &clk_pixel_ops,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_rcg2 pclk1_clk_src = {
+	.cmd_rcgr = 0x2020,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = mmss_xo_dsi0pll_dsi1pll_map,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "pclk1_clk_src",
+		.parent_names = mmss_xo_dsi0pll_dsi1pll,
+		.num_parents = 3,
+		.ops = &clk_pixel_ops,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct freq_tbl ftbl_mdp_clk_src[] = {
+	F(85714286, P_GPLL0, 7, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(171428571, P_GPLL0, 3.5, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(275000000, P_MMPLL5, 3, 0, 0),
+	F(300000000, P_GPLL0, 2, 0, 0),
+	F(330000000, P_MMPLL5, 2.5, 0, 0),
+	F(412500000, P_MMPLL5, 2, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 mdp_clk_src = {
+	.cmd_rcgr = 0x2040,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll5_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_mdp_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mdp_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll5_gpll0_gpll0_div,
+		.num_parents = 5,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct freq_tbl extpclk_freq_tbl[] = {
+	{ .src = P_HDMIPLL },
+	{ }
+};
+
+static struct clk_rcg2 extpclk_clk_src = {
+	.cmd_rcgr = 0x2060,
+	.hid_width = 5,
+	.parent_map = mmss_xo_hdmi_map,
+	.freq_tbl = extpclk_freq_tbl,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "extpclk_clk_src",
+		.parent_names = mmss_xo_hdmi,
+		.num_parents = 2,
+		.ops = &clk_byte_ops,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct freq_tbl ftbl_mdss_vsync_clk[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 vsync_clk_src = {
+	.cmd_rcgr = 0x2080,
+	.hid_width = 5,
+	.parent_map = mmss_xo_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_mdss_vsync_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "vsync_clk_src",
+		.parent_names = mmss_xo_gpll0_gpll0_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct freq_tbl ftbl_mdss_hdmi_clk[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 hdmi_clk_src = {
+	.cmd_rcgr = 0x2100,
+	.hid_width = 5,
+	.parent_map = mmss_xo_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_mdss_hdmi_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "hdmi_clk_src",
+		.parent_names = mmss_xo_gpll0_gpll0_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 byte0_clk_src = {
+	.cmd_rcgr = 0x2120,
+	.hid_width = 5,
+	.parent_map = mmss_xo_dsibyte_map,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "byte0_clk_src",
+		.parent_names = mmss_xo_dsibyte,
+		.num_parents = 3,
+		.ops = &clk_byte2_ops,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_rcg2 byte1_clk_src = {
+	.cmd_rcgr = 0x2140,
+	.hid_width = 5,
+	.parent_map = mmss_xo_dsibyte_map,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "byte1_clk_src",
+		.parent_names = mmss_xo_dsibyte,
+		.num_parents = 3,
+		.ops = &clk_byte2_ops,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct freq_tbl ftbl_mdss_esc0_1_clk[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 esc0_clk_src = {
+	.cmd_rcgr = 0x2160,
+	.hid_width = 5,
+	.parent_map = mmss_xo_dsibyte_map,
+	.freq_tbl = ftbl_mdss_esc0_1_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "esc0_clk_src",
+		.parent_names = mmss_xo_dsibyte,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 esc1_clk_src = {
+	.cmd_rcgr = 0x2180,
+	.hid_width = 5,
+	.parent_map = mmss_xo_dsibyte_map,
+	.freq_tbl = ftbl_mdss_esc0_1_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "esc1_clk_src",
+		.parent_names = mmss_xo_dsibyte,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_camss_gp0_clk_src[] = {
+	F(10000, P_XO, 16, 1, 120),
+	F(24000, P_XO, 16, 1, 50),
+	F(6000000, P_GPLL0_DIV, 10, 1, 5),
+	F(12000000, P_GPLL0_DIV, 1, 1, 25),
+	F(13000000, P_GPLL0_DIV, 2, 13, 150),
+	F(24000000, P_GPLL0_DIV, 1, 2, 25),
+	{ }
+};
+
+static struct clk_rcg2 camss_gp0_clk_src = {
+	.cmd_rcgr = 0x3420,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_camss_gp0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "camss_gp0_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+		.num_parents = 5,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 camss_gp1_clk_src = {
+	.cmd_rcgr = 0x3450,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_camss_gp0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "camss_gp1_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+		.num_parents = 5,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_mclk0_clk_src[] = {
+	F(4800000, P_XO, 4, 0, 0),
+	F(6000000, P_GPLL0_DIV, 10, 1, 5),
+	F(8000000, P_GPLL0_DIV, 1, 2, 75),
+	F(9600000, P_XO, 2, 0, 0),
+	F(16666667, P_GPLL0_DIV, 2, 1, 9),
+	F(19200000, P_XO, 1, 0, 0),
+	F(24000000, P_GPLL0_DIV, 1, 2, 25),
+	F(33333333, P_GPLL0_DIV, 1, 1, 9),
+	F(48000000, P_GPLL0, 1, 2, 25),
+	F(66666667, P_GPLL0, 1, 1, 9),
+	{ }
+};
+
+static struct clk_rcg2 mclk0_clk_src = {
+	.cmd_rcgr = 0x3360,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_mclk0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mclk0_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+		.num_parents = 5,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 mclk1_clk_src = {
+	.cmd_rcgr = 0x3390,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_mclk0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mclk1_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+		.num_parents = 5,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 mclk2_clk_src = {
+	.cmd_rcgr = 0x33c0,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_mclk0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mclk2_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+		.num_parents = 5,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 mclk3_clk_src = {
+	.cmd_rcgr = 0x33f0,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_mclk0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "mclk3_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+		.num_parents = 5,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cci_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(37500000, P_GPLL0, 16, 0, 0),
+	F(50000000, P_GPLL0, 12, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cci_clk_src = {
+	.cmd_rcgr = 0x3300,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_cci_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "cci_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+		.num_parents = 5,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_csi0phytimer_clk_src[] = {
+	F(100000000, P_GPLL0_DIV, 3, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(266666667, P_MMPLL0, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 csi0phytimer_clk_src = {
+	.cmd_rcgr = 0x3000,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_csi0phytimer_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "csi0phytimer_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 csi1phytimer_clk_src = {
+	.cmd_rcgr = 0x3030,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_csi0phytimer_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "csi1phytimer_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 csi2phytimer_clk_src = {
+	.cmd_rcgr = 0x3060,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_csi0phytimer_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "csi2phytimer_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_csiphy0_3p_clk_src[] = {
+	F(100000000, P_GPLL0_DIV, 3, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(320000000, P_MMPLL4, 3, 0, 0),
+	F(384000000, P_MMPLL4, 2.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 csiphy0_3p_clk_src = {
+	.cmd_rcgr = 0x3240,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_csiphy0_3p_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "csiphy0_3p_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 csiphy1_3p_clk_src = {
+	.cmd_rcgr = 0x3260,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_csiphy0_3p_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "csiphy1_3p_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 csiphy2_3p_clk_src = {
+	.cmd_rcgr = 0x3280,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_csiphy0_3p_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "csiphy2_3p_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_jpeg0_clk_src[] = {
+	F(75000000, P_GPLL0_DIV, 4, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(228571429, P_MMPLL0, 3.5, 0, 0),
+	F(266666667, P_MMPLL0, 3, 0, 0),
+	F(320000000, P_MMPLL0, 2.5, 0, 0),
+	F(480000000, P_MMPLL4, 2, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 jpeg0_clk_src = {
+	.cmd_rcgr = 0x3500,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_jpeg0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "jpeg0_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_jpeg2_clk_src[] = {
+	F(75000000, P_GPLL0_DIV, 4, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(228571429, P_MMPLL0, 3.5, 0, 0),
+	F(266666667, P_MMPLL0, 3, 0, 0),
+	F(320000000, P_MMPLL0, 2.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 jpeg2_clk_src = {
+	.cmd_rcgr = 0x3540,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_jpeg2_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "jpeg2_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 jpeg_dma_clk_src = {
+	.cmd_rcgr = 0x3560,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_jpeg0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "jpeg_dma_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_vfe0_clk_src[] = {
+	F(75000000, P_GPLL0_DIV, 4, 0, 0),
+	F(100000000, P_GPLL0_DIV, 3, 0, 0),
+	F(300000000, P_GPLL0, 2, 0, 0),
+	F(320000000, P_MMPLL0, 2.5, 0, 0),
+	F(480000000, P_MMPLL4, 2, 0, 0),
+	F(600000000, P_GPLL0, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 vfe0_clk_src = {
+	.cmd_rcgr = 0x3600,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_vfe0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "vfe0_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 vfe1_clk_src = {
+	.cmd_rcgr = 0x3620,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_vfe0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "vfe1_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_cpp_clk_src[] = {
+	F(100000000, P_GPLL0_DIV, 3, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(320000000, P_MMPLL0, 2.5, 0, 0),
+	F(480000000, P_MMPLL4, 2, 0, 0),
+	F(640000000, P_MMPLL4, 1.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 cpp_clk_src = {
+	.cmd_rcgr = 0x3640,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_cpp_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "cpp_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_csi0_clk_src[] = {
+	F(100000000, P_GPLL0_DIV, 3, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(266666667, P_MMPLL0, 3, 0, 0),
+	F(480000000, P_MMPLL4, 2, 0, 0),
+	F(600000000, P_GPLL0, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 csi0_clk_src = {
+	.cmd_rcgr = 0x3090,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_csi0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "csi0_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 csi1_clk_src = {
+	.cmd_rcgr = 0x3100,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_csi0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "csi1_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 csi2_clk_src = {
+	.cmd_rcgr = 0x3160,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_csi0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "csi2_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 csi3_clk_src = {
+	.cmd_rcgr = 0x31c0,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_csi0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "csi3_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
+		.num_parents = 7,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_fd_core_clk_src[] = {
+	F(100000000, P_GPLL0_DIV, 3, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(400000000, P_MMPLL0, 2, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 fd_core_clk_src = {
+	.cmd_rcgr = 0x3b00,
+	.hid_width = 5,
+	.parent_map = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div_map,
+	.freq_tbl = ftbl_fd_core_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "fd_core_clk_src",
+		.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
+		.num_parents = 5,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_branch mmss_mmagic_ahb_clk = {
+	.halt_reg = 0x5024,
+	.clkr = {
+		.enable_reg = 0x5024,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmss_mmagic_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mmss_mmagic_cfg_ahb_clk = {
+	.halt_reg = 0x5054,
+	.clkr = {
+		.enable_reg = 0x5054,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmss_mmagic_cfg_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mmss_misc_ahb_clk = {
+	.halt_reg = 0x5018,
+	.clkr = {
+		.enable_reg = 0x5018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmss_misc_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mmss_misc_cxo_clk = {
+	.halt_reg = 0x5014,
+	.clkr = {
+		.enable_reg = 0x5014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmss_misc_cxo_clk",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mmss_mmagic_axi_clk = {
+	.halt_reg = 0x506c,
+	.clkr = {
+		.enable_reg = 0x506c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmss_mmagic_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mmss_mmagic_maxi_clk = {
+	.halt_reg = 0x5074,
+	.clkr = {
+		.enable_reg = 0x5074,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmss_mmagic_maxi_clk",
+			.parent_names = (const char *[]){ "maxi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mmagic_camss_axi_clk = {
+	.halt_reg = 0x3c44,
+	.clkr = {
+		.enable_reg = 0x3c44,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmagic_camss_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mmagic_camss_noc_cfg_ahb_clk = {
+	.halt_reg = 0x3c48,
+	.clkr = {
+		.enable_reg = 0x3c48,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmagic_camss_noc_cfg_ahb_clk",
+			.parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch smmu_vfe_ahb_clk = {
+	.halt_reg = 0x3c04,
+	.clkr = {
+		.enable_reg = 0x3c04,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "smmu_vfe_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch smmu_vfe_axi_clk = {
+	.halt_reg = 0x3c08,
+	.clkr = {
+		.enable_reg = 0x3c08,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "smmu_vfe_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch smmu_cpp_ahb_clk = {
+	.halt_reg = 0x3c14,
+	.clkr = {
+		.enable_reg = 0x3c14,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "smmu_cpp_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch smmu_cpp_axi_clk = {
+	.halt_reg = 0x3c18,
+	.clkr = {
+		.enable_reg = 0x3c18,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "smmu_cpp_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch smmu_jpeg_ahb_clk = {
+	.halt_reg = 0x3c24,
+	.clkr = {
+		.enable_reg = 0x3c24,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "smmu_jpeg_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch smmu_jpeg_axi_clk = {
+	.halt_reg = 0x3c28,
+	.clkr = {
+		.enable_reg = 0x3c28,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "smmu_jpeg_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mmagic_mdss_axi_clk = {
+	.halt_reg = 0x2474,
+	.clkr = {
+		.enable_reg = 0x2474,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmagic_mdss_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mmagic_mdss_noc_cfg_ahb_clk = {
+	.halt_reg = 0x2478,
+	.clkr = {
+		.enable_reg = 0x2478,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmagic_mdss_noc_cfg_ahb_clk",
+			.parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch smmu_rot_ahb_clk = {
+	.halt_reg = 0x2444,
+	.clkr = {
+		.enable_reg = 0x2444,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "smmu_rot_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch smmu_rot_axi_clk = {
+	.halt_reg = 0x2448,
+	.clkr = {
+		.enable_reg = 0x2448,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "smmu_rot_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch smmu_mdp_ahb_clk = {
+	.halt_reg = 0x2454,
+	.clkr = {
+		.enable_reg = 0x2454,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "smmu_mdp_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch smmu_mdp_axi_clk = {
+	.halt_reg = 0x2458,
+	.clkr = {
+		.enable_reg = 0x2458,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "smmu_mdp_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mmagic_video_axi_clk = {
+	.halt_reg = 0x1194,
+	.clkr = {
+		.enable_reg = 0x1194,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmagic_video_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mmagic_video_noc_cfg_ahb_clk = {
+	.halt_reg = 0x1198,
+	.clkr = {
+		.enable_reg = 0x1198,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmagic_video_noc_cfg_ahb_clk",
+			.parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch smmu_video_ahb_clk = {
+	.halt_reg = 0x1174,
+	.clkr = {
+		.enable_reg = 0x1174,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "smmu_video_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch smmu_video_axi_clk = {
+	.halt_reg = 0x1178,
+	.clkr = {
+		.enable_reg = 0x1178,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "smmu_video_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mmagic_bimc_axi_clk = {
+	.halt_reg = 0x5294,
+	.clkr = {
+		.enable_reg = 0x5294,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmagic_bimc_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mmagic_bimc_noc_cfg_ahb_clk = {
+	.halt_reg = 0x5298,
+	.clkr = {
+		.enable_reg = 0x5298,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmagic_bimc_noc_cfg_ahb_clk",
+			.parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_gx_gfx3d_clk = {
+	.halt_reg = 0x4028,
+	.clkr = {
+		.enable_reg = 0x4028,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_gx_gfx3d_clk",
+			.parent_names = (const char *[]){ "gfx3d_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_gx_rbbmtimer_clk = {
+	.halt_reg = 0x40b0,
+	.clkr = {
+		.enable_reg = 0x40b0,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_gx_rbbmtimer_clk",
+			.parent_names = (const char *[]){ "rbbmtimer_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_ahb_clk = {
+	.halt_reg = 0x403c,
+	.clkr = {
+		.enable_reg = 0x403c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gpu_aon_isense_clk = {
+	.halt_reg = 0x4044,
+	.clkr = {
+		.enable_reg = 0x4044,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpu_aon_isense_clk",
+			.parent_names = (const char *[]){ "isense_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch vmem_maxi_clk = {
+	.halt_reg = 0x1204,
+	.clkr = {
+		.enable_reg = 0x1204,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "vmem_maxi_clk",
+			.parent_names = (const char *[]){ "maxi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch vmem_ahb_clk = {
+	.halt_reg = 0x1208,
+	.clkr = {
+		.enable_reg = 0x1208,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "vmem_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mmss_rbcpr_clk = {
+	.halt_reg = 0x4084,
+	.clkr = {
+		.enable_reg = 0x4084,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmss_rbcpr_clk",
+			.parent_names = (const char *[]){ "rbcpr_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mmss_rbcpr_ahb_clk = {
+	.halt_reg = 0x4088,
+	.clkr = {
+		.enable_reg = 0x4088,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mmss_rbcpr_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch video_core_clk = {
+	.halt_reg = 0x1028,
+	.clkr = {
+		.enable_reg = 0x1028,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "video_core_clk",
+			.parent_names = (const char *[]){ "video_core_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch video_axi_clk = {
+	.halt_reg = 0x1034,
+	.clkr = {
+		.enable_reg = 0x1034,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "video_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch video_maxi_clk = {
+	.halt_reg = 0x1038,
+	.clkr = {
+		.enable_reg = 0x1038,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "video_maxi_clk",
+			.parent_names = (const char *[]){ "maxi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch video_ahb_clk = {
+	.halt_reg = 0x1030,
+	.clkr = {
+		.enable_reg = 0x1030,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "video_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch video_subcore0_clk = {
+	.halt_reg = 0x1048,
+	.clkr = {
+		.enable_reg = 0x1048,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "video_subcore0_clk",
+			.parent_names = (const char *[]){ "video_subcore0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch video_subcore1_clk = {
+	.halt_reg = 0x104c,
+	.clkr = {
+		.enable_reg = 0x104c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "video_subcore1_clk",
+			.parent_names = (const char *[]){ "video_subcore1_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mdss_ahb_clk = {
+	.halt_reg = 0x2308,
+	.clkr = {
+		.enable_reg = 0x2308,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mdss_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mdss_hdmi_ahb_clk = {
+	.halt_reg = 0x230c,
+	.clkr = {
+		.enable_reg = 0x230c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mdss_hdmi_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mdss_axi_clk = {
+	.halt_reg = 0x2310,
+	.clkr = {
+		.enable_reg = 0x2310,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mdss_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mdss_pclk0_clk = {
+	.halt_reg = 0x2314,
+	.clkr = {
+		.enable_reg = 0x2314,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mdss_pclk0_clk",
+			.parent_names = (const char *[]){ "pclk0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mdss_pclk1_clk = {
+	.halt_reg = 0x2318,
+	.clkr = {
+		.enable_reg = 0x2318,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mdss_pclk1_clk",
+			.parent_names = (const char *[]){ "pclk1_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mdss_mdp_clk = {
+	.halt_reg = 0x231c,
+	.clkr = {
+		.enable_reg = 0x231c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mdss_mdp_clk",
+			.parent_names = (const char *[]){ "mdp_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mdss_extpclk_clk = {
+	.halt_reg = 0x2324,
+	.clkr = {
+		.enable_reg = 0x2324,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mdss_extpclk_clk",
+			.parent_names = (const char *[]){ "extpclk_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mdss_vsync_clk = {
+	.halt_reg = 0x2328,
+	.clkr = {
+		.enable_reg = 0x2328,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mdss_vsync_clk",
+			.parent_names = (const char *[]){ "vsync_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mdss_hdmi_clk = {
+	.halt_reg = 0x2338,
+	.clkr = {
+		.enable_reg = 0x2338,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mdss_hdmi_clk",
+			.parent_names = (const char *[]){ "hdmi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mdss_byte0_clk = {
+	.halt_reg = 0x233c,
+	.clkr = {
+		.enable_reg = 0x233c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mdss_byte0_clk",
+			.parent_names = (const char *[]){ "byte0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mdss_byte1_clk = {
+	.halt_reg = 0x2340,
+	.clkr = {
+		.enable_reg = 0x2340,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mdss_byte1_clk",
+			.parent_names = (const char *[]){ "byte1_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mdss_esc0_clk = {
+	.halt_reg = 0x2344,
+	.clkr = {
+		.enable_reg = 0x2344,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mdss_esc0_clk",
+			.parent_names = (const char *[]){ "esc0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch mdss_esc1_clk = {
+	.halt_reg = 0x2348,
+	.clkr = {
+		.enable_reg = 0x2348,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "mdss_esc1_clk",
+			.parent_names = (const char *[]){ "esc1_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_top_ahb_clk = {
+	.halt_reg = 0x3484,
+	.clkr = {
+		.enable_reg = 0x3484,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_top_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_ahb_clk = {
+	.halt_reg = 0x348c,
+	.clkr = {
+		.enable_reg = 0x348c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_micro_ahb_clk = {
+	.halt_reg = 0x3494,
+	.clkr = {
+		.enable_reg = 0x3494,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_micro_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_gp0_clk = {
+	.halt_reg = 0x3444,
+	.clkr = {
+		.enable_reg = 0x3444,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_gp0_clk",
+			.parent_names = (const char *[]){ "camss_gp0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_gp1_clk = {
+	.halt_reg = 0x3474,
+	.clkr = {
+		.enable_reg = 0x3474,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_gp1_clk",
+			.parent_names = (const char *[]){ "camss_gp1_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_mclk0_clk = {
+	.halt_reg = 0x3384,
+	.clkr = {
+		.enable_reg = 0x3384,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_mclk0_clk",
+			.parent_names = (const char *[]){ "mclk0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_mclk1_clk = {
+	.halt_reg = 0x33b4,
+	.clkr = {
+		.enable_reg = 0x33b4,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_mclk1_clk",
+			.parent_names = (const char *[]){ "mclk1_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_mclk2_clk = {
+	.halt_reg = 0x33e4,
+	.clkr = {
+		.enable_reg = 0x33e4,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_mclk2_clk",
+			.parent_names = (const char *[]){ "mclk2_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_mclk3_clk = {
+	.halt_reg = 0x3414,
+	.clkr = {
+		.enable_reg = 0x3414,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_mclk3_clk",
+			.parent_names = (const char *[]){ "mclk3_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_cci_clk = {
+	.halt_reg = 0x3344,
+	.clkr = {
+		.enable_reg = 0x3344,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_cci_clk",
+			.parent_names = (const char *[]){ "cci_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_cci_ahb_clk = {
+	.halt_reg = 0x3348,
+	.clkr = {
+		.enable_reg = 0x3348,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_cci_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi0phytimer_clk = {
+	.halt_reg = 0x3024,
+	.clkr = {
+		.enable_reg = 0x3024,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi0phytimer_clk",
+			.parent_names = (const char *[]){ "csi0phytimer_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi1phytimer_clk = {
+	.halt_reg = 0x3054,
+	.clkr = {
+		.enable_reg = 0x3054,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi1phytimer_clk",
+			.parent_names = (const char *[]){ "csi1phytimer_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi2phytimer_clk = {
+	.halt_reg = 0x3084,
+	.clkr = {
+		.enable_reg = 0x3084,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi2phytimer_clk",
+			.parent_names = (const char *[]){ "csi2phytimer_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csiphy0_3p_clk = {
+	.halt_reg = 0x3234,
+	.clkr = {
+		.enable_reg = 0x3234,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csiphy0_3p_clk",
+			.parent_names = (const char *[]){ "csiphy0_3p_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csiphy1_3p_clk = {
+	.halt_reg = 0x3254,
+	.clkr = {
+		.enable_reg = 0x3254,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csiphy1_3p_clk",
+			.parent_names = (const char *[]){ "csiphy1_3p_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csiphy2_3p_clk = {
+	.halt_reg = 0x3274,
+	.clkr = {
+		.enable_reg = 0x3274,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csiphy2_3p_clk",
+			.parent_names = (const char *[]){ "csiphy2_3p_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_jpeg0_clk = {
+	.halt_reg = 0x35a8,
+	.clkr = {
+		.enable_reg = 0x35a8,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_jpeg0_clk",
+			.parent_names = (const char *[]){ "jpeg0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_jpeg2_clk = {
+	.halt_reg = 0x35b0,
+	.clkr = {
+		.enable_reg = 0x35b0,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_jpeg2_clk",
+			.parent_names = (const char *[]){ "jpeg2_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_jpeg_dma_clk = {
+	.halt_reg = 0x35c0,
+	.clkr = {
+		.enable_reg = 0x35c0,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_jpeg_dma_clk",
+			.parent_names = (const char *[]){ "jpeg_dma_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_jpeg_ahb_clk = {
+	.halt_reg = 0x35b4,
+	.clkr = {
+		.enable_reg = 0x35b4,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_jpeg_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_jpeg_axi_clk = {
+	.halt_reg = 0x35b8,
+	.clkr = {
+		.enable_reg = 0x35b8,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_jpeg_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_vfe_ahb_clk = {
+	.halt_reg = 0x36b8,
+	.clkr = {
+		.enable_reg = 0x36b8,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_vfe_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_vfe_axi_clk = {
+	.halt_reg = 0x36bc,
+	.clkr = {
+		.enable_reg = 0x36bc,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_vfe_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_vfe0_clk = {
+	.halt_reg = 0x36a8,
+	.clkr = {
+		.enable_reg = 0x36a8,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_vfe0_clk",
+			.parent_names = (const char *[]){ "vfe0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_vfe0_stream_clk = {
+	.halt_reg = 0x3720,
+	.clkr = {
+		.enable_reg = 0x3720,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_vfe0_stream_clk",
+			.parent_names = (const char *[]){ "vfe0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_vfe0_ahb_clk = {
+	.halt_reg = 0x3668,
+	.clkr = {
+		.enable_reg = 0x3668,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_vfe0_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_vfe1_clk = {
+	.halt_reg = 0x36ac,
+	.clkr = {
+		.enable_reg = 0x36ac,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_vfe1_clk",
+			.parent_names = (const char *[]){ "vfe1_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_vfe1_stream_clk = {
+	.halt_reg = 0x3724,
+	.clkr = {
+		.enable_reg = 0x3724,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_vfe1_stream_clk",
+			.parent_names = (const char *[]){ "vfe1_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_vfe1_ahb_clk = {
+	.halt_reg = 0x3678,
+	.clkr = {
+		.enable_reg = 0x3678,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_vfe1_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi_vfe0_clk = {
+	.halt_reg = 0x3704,
+	.clkr = {
+		.enable_reg = 0x3704,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi_vfe0_clk",
+			.parent_names = (const char *[]){ "vfe0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi_vfe1_clk = {
+	.halt_reg = 0x3714,
+	.clkr = {
+		.enable_reg = 0x3714,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi_vfe1_clk",
+			.parent_names = (const char *[]){ "vfe1_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_cpp_vbif_ahb_clk = {
+	.halt_reg = 0x36c8,
+	.clkr = {
+		.enable_reg = 0x36c8,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_cpp_vbif_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_cpp_axi_clk = {
+	.halt_reg = 0x36c4,
+	.clkr = {
+		.enable_reg = 0x36c4,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_cpp_axi_clk",
+			.parent_names = (const char *[]){ "axi_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_cpp_clk = {
+	.halt_reg = 0x36b0,
+	.clkr = {
+		.enable_reg = 0x36b0,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_cpp_clk",
+			.parent_names = (const char *[]){ "cpp_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_cpp_ahb_clk = {
+	.halt_reg = 0x36b4,
+	.clkr = {
+		.enable_reg = 0x36b4,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_cpp_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi0_clk = {
+	.halt_reg = 0x30b4,
+	.clkr = {
+		.enable_reg = 0x30b4,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi0_clk",
+			.parent_names = (const char *[]){ "csi0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi0_ahb_clk = {
+	.halt_reg = 0x30bc,
+	.clkr = {
+		.enable_reg = 0x30bc,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi0_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi0phy_clk = {
+	.halt_reg = 0x30c4,
+	.clkr = {
+		.enable_reg = 0x30c4,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi0phy_clk",
+			.parent_names = (const char *[]){ "csi0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi0rdi_clk = {
+	.halt_reg = 0x30d4,
+	.clkr = {
+		.enable_reg = 0x30d4,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi0rdi_clk",
+			.parent_names = (const char *[]){ "csi0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi0pix_clk = {
+	.halt_reg = 0x30e4,
+	.clkr = {
+		.enable_reg = 0x30e4,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi0pix_clk",
+			.parent_names = (const char *[]){ "csi0_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi1_clk = {
+	.halt_reg = 0x3124,
+	.clkr = {
+		.enable_reg = 0x3124,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi1_clk",
+			.parent_names = (const char *[]){ "csi1_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi1_ahb_clk = {
+	.halt_reg = 0x3128,
+	.clkr = {
+		.enable_reg = 0x3128,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi1_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi1phy_clk = {
+	.halt_reg = 0x3134,
+	.clkr = {
+		.enable_reg = 0x3134,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi1phy_clk",
+			.parent_names = (const char *[]){ "csi1_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi1rdi_clk = {
+	.halt_reg = 0x3144,
+	.clkr = {
+		.enable_reg = 0x3144,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi1rdi_clk",
+			.parent_names = (const char *[]){ "csi1_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi1pix_clk = {
+	.halt_reg = 0x3154,
+	.clkr = {
+		.enable_reg = 0x3154,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi1pix_clk",
+			.parent_names = (const char *[]){ "csi1_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi2_clk = {
+	.halt_reg = 0x3184,
+	.clkr = {
+		.enable_reg = 0x3184,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi2_clk",
+			.parent_names = (const char *[]){ "csi2_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi2_ahb_clk = {
+	.halt_reg = 0x3188,
+	.clkr = {
+		.enable_reg = 0x3188,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi2_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi2phy_clk = {
+	.halt_reg = 0x3194,
+	.clkr = {
+		.enable_reg = 0x3194,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi2phy_clk",
+			.parent_names = (const char *[]){ "csi2_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi2rdi_clk = {
+	.halt_reg = 0x31a4,
+	.clkr = {
+		.enable_reg = 0x31a4,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi2rdi_clk",
+			.parent_names = (const char *[]){ "csi2_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi2pix_clk = {
+	.halt_reg = 0x31b4,
+	.clkr = {
+		.enable_reg = 0x31b4,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi2pix_clk",
+			.parent_names = (const char *[]){ "csi2_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi3_clk = {
+	.halt_reg = 0x31e4,
+	.clkr = {
+		.enable_reg = 0x31e4,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi3_clk",
+			.parent_names = (const char *[]){ "csi3_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi3_ahb_clk = {
+	.halt_reg = 0x31e8,
+	.clkr = {
+		.enable_reg = 0x31e8,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi3_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi3phy_clk = {
+	.halt_reg = 0x31f4,
+	.clkr = {
+		.enable_reg = 0x31f4,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi3phy_clk",
+			.parent_names = (const char *[]){ "csi3_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi3rdi_clk = {
+	.halt_reg = 0x3204,
+	.clkr = {
+		.enable_reg = 0x3204,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi3rdi_clk",
+			.parent_names = (const char *[]){ "csi3_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_csi3pix_clk = {
+	.halt_reg = 0x3214,
+	.clkr = {
+		.enable_reg = 0x3214,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_csi3pix_clk",
+			.parent_names = (const char *[]){ "csi3_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch camss_ispif_ahb_clk = {
+	.halt_reg = 0x3224,
+	.clkr = {
+		.enable_reg = 0x3224,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "camss_ispif_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch fd_core_clk = {
+	.halt_reg = 0x3b68,
+	.clkr = {
+		.enable_reg = 0x3b68,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "fd_core_clk",
+			.parent_names = (const char *[]){ "fd_core_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch fd_core_uar_clk = {
+	.halt_reg = 0x3b6c,
+	.clkr = {
+		.enable_reg = 0x3b6c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "fd_core_uar_clk",
+			.parent_names = (const char *[]){ "fd_core_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch fd_ahb_clk = {
+	.halt_reg = 0x3ba74,
+	.clkr = {
+		.enable_reg = 0x3ba74,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "fd_ahb_clk",
+			.parent_names = (const char *[]){ "ahb_clk_src" },
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_hw *mmcc_msm8996_hws[] = {
+	&gpll0_div.hw,
+};
+
+static struct clk_regmap *mmcc_msm8996_clocks[] = {
+	[MMPLL0_EARLY] = &mmpll0_early.clkr,
+	[MMPLL0_PLL] = &mmpll0.clkr,
+	[MMPLL1_EARLY] = &mmpll1_early.clkr,
+	[MMPLL1_PLL] = &mmpll1.clkr,
+	[MMPLL2_EARLY] = &mmpll2_early.clkr,
+	[MMPLL2_PLL] = &mmpll2.clkr,
+	[MMPLL3_EARLY] = &mmpll3_early.clkr,
+	[MMPLL3_PLL] = &mmpll3.clkr,
+	[MMPLL4_EARLY] = &mmpll4_early.clkr,
+	[MMPLL4_PLL] = &mmpll4.clkr,
+	[MMPLL5_EARLY] = &mmpll5_early.clkr,
+	[MMPLL5_PLL] = &mmpll5.clkr,
+	[MMPLL8_EARLY] = &mmpll8_early.clkr,
+	[MMPLL8_PLL] = &mmpll8.clkr,
+	[MMPLL9_EARLY] = &mmpll9_early.clkr,
+	[MMPLL9_PLL] = &mmpll9.clkr,
+	[AHB_CLK_SRC] = &ahb_clk_src.clkr,
+	[AXI_CLK_SRC] = &axi_clk_src.clkr,
+	[MAXI_CLK_SRC] = &maxi_clk_src.clkr,
+	[GFX3D_CLK_SRC] = &gfx3d_clk_src.clkr,
+	[RBBMTIMER_CLK_SRC] = &rbbmtimer_clk_src.clkr,
+	[ISENSE_CLK_SRC] = &isense_clk_src.clkr,
+	[RBCPR_CLK_SRC] = &rbcpr_clk_src.clkr,
+	[VIDEO_CORE_CLK_SRC] = &video_core_clk_src.clkr,
+	[VIDEO_SUBCORE0_CLK_SRC] = &video_subcore0_clk_src.clkr,
+	[VIDEO_SUBCORE1_CLK_SRC] = &video_subcore1_clk_src.clkr,
+	[PCLK0_CLK_SRC] = &pclk0_clk_src.clkr,
+	[PCLK1_CLK_SRC] = &pclk1_clk_src.clkr,
+	[MDP_CLK_SRC] = &mdp_clk_src.clkr,
+	[EXTPCLK_CLK_SRC] = &extpclk_clk_src.clkr,
+	[VSYNC_CLK_SRC] = &vsync_clk_src.clkr,
+	[HDMI_CLK_SRC] = &hdmi_clk_src.clkr,
+	[BYTE0_CLK_SRC] = &byte0_clk_src.clkr,
+	[BYTE1_CLK_SRC] = &byte1_clk_src.clkr,
+	[ESC0_CLK_SRC] = &esc0_clk_src.clkr,
+	[ESC1_CLK_SRC] = &esc1_clk_src.clkr,
+	[CAMSS_GP0_CLK_SRC] = &camss_gp0_clk_src.clkr,
+	[CAMSS_GP1_CLK_SRC] = &camss_gp1_clk_src.clkr,
+	[MCLK0_CLK_SRC] = &mclk0_clk_src.clkr,
+	[MCLK1_CLK_SRC] = &mclk1_clk_src.clkr,
+	[MCLK2_CLK_SRC] = &mclk2_clk_src.clkr,
+	[MCLK3_CLK_SRC] = &mclk3_clk_src.clkr,
+	[CCI_CLK_SRC] = &cci_clk_src.clkr,
+	[CSI0PHYTIMER_CLK_SRC] = &csi0phytimer_clk_src.clkr,
+	[CSI1PHYTIMER_CLK_SRC] = &csi1phytimer_clk_src.clkr,
+	[CSI2PHYTIMER_CLK_SRC] = &csi2phytimer_clk_src.clkr,
+	[CSIPHY0_3P_CLK_SRC] = &csiphy0_3p_clk_src.clkr,
+	[CSIPHY1_3P_CLK_SRC] = &csiphy1_3p_clk_src.clkr,
+	[CSIPHY2_3P_CLK_SRC] = &csiphy2_3p_clk_src.clkr,
+	[JPEG0_CLK_SRC] = &jpeg0_clk_src.clkr,
+	[JPEG2_CLK_SRC] = &jpeg2_clk_src.clkr,
+	[JPEG_DMA_CLK_SRC] = &jpeg_dma_clk_src.clkr,
+	[VFE0_CLK_SRC] = &vfe0_clk_src.clkr,
+	[VFE1_CLK_SRC] = &vfe1_clk_src.clkr,
+	[CPP_CLK_SRC] = &cpp_clk_src.clkr,
+	[CSI0_CLK_SRC] = &csi0_clk_src.clkr,
+	[CSI1_CLK_SRC] = &csi1_clk_src.clkr,
+	[CSI2_CLK_SRC] = &csi2_clk_src.clkr,
+	[CSI3_CLK_SRC] = &csi3_clk_src.clkr,
+	[FD_CORE_CLK_SRC] = &fd_core_clk_src.clkr,
+	[MMSS_MMAGIC_AHB_CLK] = &mmss_mmagic_ahb_clk.clkr,
+	[MMSS_MMAGIC_CFG_AHB_CLK] = &mmss_mmagic_cfg_ahb_clk.clkr,
+	[MMSS_MISC_AHB_CLK] = &mmss_misc_ahb_clk.clkr,
+	[MMSS_MISC_CXO_CLK] = &mmss_misc_cxo_clk.clkr,
+	[MMSS_MMAGIC_AXI_CLK] = &mmss_mmagic_axi_clk.clkr,
+	[MMSS_MMAGIC_MAXI_CLK] = &mmss_mmagic_maxi_clk.clkr,
+	[MMAGIC_CAMSS_AXI_CLK] = &mmagic_camss_axi_clk.clkr,
+	[MMAGIC_CAMSS_NOC_CFG_AHB_CLK] = &mmagic_camss_noc_cfg_ahb_clk.clkr,
+	[SMMU_VFE_AHB_CLK] = &smmu_vfe_ahb_clk.clkr,
+	[SMMU_VFE_AXI_CLK] = &smmu_vfe_axi_clk.clkr,
+	[SMMU_CPP_AHB_CLK] = &smmu_cpp_ahb_clk.clkr,
+	[SMMU_CPP_AXI_CLK] = &smmu_cpp_axi_clk.clkr,
+	[SMMU_JPEG_AHB_CLK] = &smmu_jpeg_ahb_clk.clkr,
+	[SMMU_JPEG_AXI_CLK] = &smmu_jpeg_axi_clk.clkr,
+	[MMAGIC_MDSS_AXI_CLK] = &mmagic_mdss_axi_clk.clkr,
+	[MMAGIC_MDSS_NOC_CFG_AHB_CLK] = &mmagic_mdss_noc_cfg_ahb_clk.clkr,
+	[SMMU_ROT_AHB_CLK] = &smmu_rot_ahb_clk.clkr,
+	[SMMU_ROT_AXI_CLK] = &smmu_rot_axi_clk.clkr,
+	[SMMU_MDP_AHB_CLK] = &smmu_mdp_ahb_clk.clkr,
+	[SMMU_MDP_AXI_CLK] = &smmu_mdp_axi_clk.clkr,
+	[MMAGIC_VIDEO_AXI_CLK] = &mmagic_video_axi_clk.clkr,
+	[MMAGIC_VIDEO_NOC_CFG_AHB_CLK] = &mmagic_video_noc_cfg_ahb_clk.clkr,
+	[SMMU_VIDEO_AHB_CLK] = &smmu_video_ahb_clk.clkr,
+	[SMMU_VIDEO_AXI_CLK] = &smmu_video_axi_clk.clkr,
+	[MMAGIC_BIMC_AXI_CLK] = &mmagic_bimc_axi_clk.clkr,
+	[MMAGIC_BIMC_NOC_CFG_AHB_CLK] = &mmagic_bimc_noc_cfg_ahb_clk.clkr,
+	[GPU_GX_GFX3D_CLK] = &gpu_gx_gfx3d_clk.clkr,
+	[GPU_GX_RBBMTIMER_CLK] = &gpu_gx_rbbmtimer_clk.clkr,
+	[GPU_AHB_CLK] = &gpu_ahb_clk.clkr,
+	[GPU_AON_ISENSE_CLK] = &gpu_aon_isense_clk.clkr,
+	[VMEM_MAXI_CLK] = &vmem_maxi_clk.clkr,
+	[VMEM_AHB_CLK] = &vmem_ahb_clk.clkr,
+	[MMSS_RBCPR_CLK] = &mmss_rbcpr_clk.clkr,
+	[MMSS_RBCPR_AHB_CLK] = &mmss_rbcpr_ahb_clk.clkr,
+	[VIDEO_CORE_CLK] = &video_core_clk.clkr,
+	[VIDEO_AXI_CLK] = &video_axi_clk.clkr,
+	[VIDEO_MAXI_CLK] = &video_maxi_clk.clkr,
+	[VIDEO_AHB_CLK] = &video_ahb_clk.clkr,
+	[VIDEO_SUBCORE0_CLK] = &video_subcore0_clk.clkr,
+	[VIDEO_SUBCORE1_CLK] = &video_subcore1_clk.clkr,
+	[MDSS_AHB_CLK] = &mdss_ahb_clk.clkr,
+	[MDSS_HDMI_AHB_CLK] = &mdss_hdmi_ahb_clk.clkr,
+	[MDSS_AXI_CLK] = &mdss_axi_clk.clkr,
+	[MDSS_PCLK0_CLK] = &mdss_pclk0_clk.clkr,
+	[MDSS_PCLK1_CLK] = &mdss_pclk1_clk.clkr,
+	[MDSS_MDP_CLK] = &mdss_mdp_clk.clkr,
+	[MDSS_EXTPCLK_CLK] = &mdss_extpclk_clk.clkr,
+	[MDSS_VSYNC_CLK] = &mdss_vsync_clk.clkr,
+	[MDSS_HDMI_CLK] = &mdss_hdmi_clk.clkr,
+	[MDSS_BYTE0_CLK] = &mdss_byte0_clk.clkr,
+	[MDSS_BYTE1_CLK] = &mdss_byte1_clk.clkr,
+	[MDSS_ESC0_CLK] = &mdss_esc0_clk.clkr,
+	[MDSS_ESC1_CLK] = &mdss_esc1_clk.clkr,
+	[CAMSS_TOP_AHB_CLK] = &camss_top_ahb_clk.clkr,
+	[CAMSS_AHB_CLK] = &camss_ahb_clk.clkr,
+	[CAMSS_MICRO_AHB_CLK] = &camss_micro_ahb_clk.clkr,
+	[CAMSS_GP0_CLK] = &camss_gp0_clk.clkr,
+	[CAMSS_GP1_CLK] = &camss_gp1_clk.clkr,
+	[CAMSS_MCLK0_CLK] = &camss_mclk0_clk.clkr,
+	[CAMSS_MCLK1_CLK] = &camss_mclk1_clk.clkr,
+	[CAMSS_MCLK2_CLK] = &camss_mclk2_clk.clkr,
+	[CAMSS_MCLK3_CLK] = &camss_mclk3_clk.clkr,
+	[CAMSS_CCI_CLK] = &camss_cci_clk.clkr,
+	[CAMSS_CCI_AHB_CLK] = &camss_cci_ahb_clk.clkr,
+	[CAMSS_CSI0PHYTIMER_CLK] = &camss_csi0phytimer_clk.clkr,
+	[CAMSS_CSI1PHYTIMER_CLK] = &camss_csi1phytimer_clk.clkr,
+	[CAMSS_CSI2PHYTIMER_CLK] = &camss_csi2phytimer_clk.clkr,
+	[CAMSS_CSIPHY0_3P_CLK] = &camss_csiphy0_3p_clk.clkr,
+	[CAMSS_CSIPHY1_3P_CLK] = &camss_csiphy1_3p_clk.clkr,
+	[CAMSS_CSIPHY2_3P_CLK] = &camss_csiphy2_3p_clk.clkr,
+	[CAMSS_JPEG0_CLK] = &camss_jpeg0_clk.clkr,
+	[CAMSS_JPEG2_CLK] = &camss_jpeg2_clk.clkr,
+	[CAMSS_JPEG_DMA_CLK] = &camss_jpeg_dma_clk.clkr,
+	[CAMSS_JPEG_AHB_CLK] = &camss_jpeg_ahb_clk.clkr,
+	[CAMSS_JPEG_AXI_CLK] = &camss_jpeg_axi_clk.clkr,
+	[CAMSS_VFE_AHB_CLK] = &camss_vfe_ahb_clk.clkr,
+	[CAMSS_VFE_AXI_CLK] = &camss_vfe_axi_clk.clkr,
+	[CAMSS_VFE0_CLK] = &camss_vfe0_clk.clkr,
+	[CAMSS_VFE0_STREAM_CLK] = &camss_vfe0_stream_clk.clkr,
+	[CAMSS_VFE0_AHB_CLK] = &camss_vfe0_ahb_clk.clkr,
+	[CAMSS_VFE1_CLK] = &camss_vfe1_clk.clkr,
+	[CAMSS_VFE1_STREAM_CLK] = &camss_vfe1_stream_clk.clkr,
+	[CAMSS_VFE1_AHB_CLK] = &camss_vfe1_ahb_clk.clkr,
+	[CAMSS_CSI_VFE0_CLK] = &camss_csi_vfe0_clk.clkr,
+	[CAMSS_CSI_VFE1_CLK] = &camss_csi_vfe1_clk.clkr,
+	[CAMSS_CPP_VBIF_AHB_CLK] = &camss_cpp_vbif_ahb_clk.clkr,
+	[CAMSS_CPP_AXI_CLK] = &camss_cpp_axi_clk.clkr,
+	[CAMSS_CPP_CLK] = &camss_cpp_clk.clkr,
+	[CAMSS_CPP_AHB_CLK] = &camss_cpp_ahb_clk.clkr,
+	[CAMSS_CSI0_CLK] = &camss_csi0_clk.clkr,
+	[CAMSS_CSI0_AHB_CLK] = &camss_csi0_ahb_clk.clkr,
+	[CAMSS_CSI0PHY_CLK] = &camss_csi0phy_clk.clkr,
+	[CAMSS_CSI0RDI_CLK] = &camss_csi0rdi_clk.clkr,
+	[CAMSS_CSI0PIX_CLK] = &camss_csi0pix_clk.clkr,
+	[CAMSS_CSI1_CLK] = &camss_csi1_clk.clkr,
+	[CAMSS_CSI1_AHB_CLK] = &camss_csi1_ahb_clk.clkr,
+	[CAMSS_CSI1PHY_CLK] = &camss_csi1phy_clk.clkr,
+	[CAMSS_CSI1RDI_CLK] = &camss_csi1rdi_clk.clkr,
+	[CAMSS_CSI1PIX_CLK] = &camss_csi1pix_clk.clkr,
+	[CAMSS_CSI2_CLK] = &camss_csi2_clk.clkr,
+	[CAMSS_CSI2_AHB_CLK] = &camss_csi2_ahb_clk.clkr,
+	[CAMSS_CSI2PHY_CLK] = &camss_csi2phy_clk.clkr,
+	[CAMSS_CSI2RDI_CLK] = &camss_csi2rdi_clk.clkr,
+	[CAMSS_CSI2PIX_CLK] = &camss_csi2pix_clk.clkr,
+	[CAMSS_CSI3_CLK] = &camss_csi3_clk.clkr,
+	[CAMSS_CSI3_AHB_CLK] = &camss_csi3_ahb_clk.clkr,
+	[CAMSS_CSI3PHY_CLK] = &camss_csi3phy_clk.clkr,
+	[CAMSS_CSI3RDI_CLK] = &camss_csi3rdi_clk.clkr,
+	[CAMSS_CSI3PIX_CLK] = &camss_csi3pix_clk.clkr,
+	[CAMSS_ISPIF_AHB_CLK] = &camss_ispif_ahb_clk.clkr,
+	[FD_CORE_CLK] = &fd_core_clk.clkr,
+	[FD_CORE_UAR_CLK] = &fd_core_uar_clk.clkr,
+	[FD_AHB_CLK] = &fd_ahb_clk.clkr,
+};
+
+static const struct qcom_reset_map mmcc_msm8996_resets[] = {
+	[MMAGICAHB_BCR] = { 0x5020 },
+	[MMAGIC_CFG_BCR] = { 0x5050 },
+	[MISC_BCR] = { 0x5010 },
+	[BTO_BCR] = { 0x5030 },
+	[MMAGICAXI_BCR] = { 0x5060 },
+	[MMAGICMAXI_BCR] = { 0x5070 },
+	[DSA_BCR] = { 0x50a0 },
+	[MMAGIC_CAMSS_BCR] = { 0x3c40 },
+	[THROTTLE_CAMSS_BCR] = { 0x3c30 },
+	[SMMU_VFE_BCR] = { 0x3c00 },
+	[SMMU_CPP_BCR] = { 0x3c10 },
+	[SMMU_JPEG_BCR] = { 0x3c20 },
+	[MMAGIC_MDSS_BCR] = { 0x2470 },
+	[THROTTLE_MDSS_BCR] = { 0x2460 },
+	[SMMU_ROT_BCR] = { 0x2440 },
+	[SMMU_MDP_BCR] = { 0x2450 },
+	[MMAGIC_VIDEO_BCR] = { 0x1190 },
+	[THROTTLE_VIDEO_BCR] = { 0x1180 },
+	[SMMU_VIDEO_BCR] = { 0x1170 },
+	[MMAGIC_BIMC_BCR] = { 0x5290 },
+	[GPU_GX_BCR] = { 0x4020 },
+	[GPU_BCR] = { 0x4030 },
+	[GPU_AON_BCR] = { 0x4040 },
+	[VMEM_BCR] = { 0x1200 },
+	[MMSS_RBCPR_BCR] = { 0x4080 },
+	[VIDEO_BCR] = { 0x1020 },
+	[MDSS_BCR] = { 0x2300 },
+	[CAMSS_TOP_BCR] = { 0x3480 },
+	[CAMSS_AHB_BCR] = { 0x3488 },
+	[CAMSS_MICRO_BCR] = { 0x3490 },
+	[CAMSS_CCI_BCR] = { 0x3340 },
+	[CAMSS_PHY0_BCR] = { 0x3020 },
+	[CAMSS_PHY1_BCR] = { 0x3050 },
+	[CAMSS_PHY2_BCR] = { 0x3080 },
+	[CAMSS_CSIPHY0_3P_BCR] = { 0x3230 },
+	[CAMSS_CSIPHY1_3P_BCR] = { 0x3250 },
+	[CAMSS_CSIPHY2_3P_BCR] = { 0x3270 },
+	[CAMSS_JPEG_BCR] = { 0x35a0 },
+	[CAMSS_VFE_BCR] = { 0x36a0 },
+	[CAMSS_VFE0_BCR] = { 0x3660 },
+	[CAMSS_VFE1_BCR] = { 0x3670 },
+	[CAMSS_CSI_VFE0_BCR] = { 0x3700 },
+	[CAMSS_CSI_VFE1_BCR] = { 0x3710 },
+	[CAMSS_CPP_TOP_BCR] = { 0x36c0 },
+	[CAMSS_CPP_BCR] = { 0x36d0 },
+	[CAMSS_CSI0_BCR] = { 0x30b0 },
+	[CAMSS_CSI0RDI_BCR] = { 0x30d0 },
+	[CAMSS_CSI0PIX_BCR] = { 0x30e0 },
+	[CAMSS_CSI1_BCR] = { 0x3120 },
+	[CAMSS_CSI1RDI_BCR] = { 0x3140 },
+	[CAMSS_CSI1PIX_BCR] = { 0x3150 },
+	[CAMSS_CSI2_BCR] = { 0x3180 },
+	[CAMSS_CSI2RDI_BCR] = { 0x31a0 },
+	[CAMSS_CSI2PIX_BCR] = { 0x31b0 },
+	[CAMSS_CSI3_BCR] = { 0x31e0 },
+	[CAMSS_CSI3RDI_BCR] = { 0x3200 },
+	[CAMSS_CSI3PIX_BCR] = { 0x3210 },
+	[CAMSS_ISPIF_BCR] = { 0x3220 },
+	[FD_BCR] = { 0x3b60 },
+	[MMSS_SPDM_RM_BCR] = { 0x300 },
+};
+
+static const struct regmap_config mmcc_msm8996_regmap_config = {
+	.reg_bits	= 32,
+	.reg_stride	= 4,
+	.val_bits	= 32,
+	.max_register	= 0xb008,
+	.fast_io	= true,
+};
+
+static const struct qcom_cc_desc mmcc_msm8996_desc = {
+	.config = &mmcc_msm8996_regmap_config,
+	.clks = mmcc_msm8996_clocks,
+	.num_clks = ARRAY_SIZE(mmcc_msm8996_clocks),
+	.resets = mmcc_msm8996_resets,
+	.num_resets = ARRAY_SIZE(mmcc_msm8996_resets),
+};
+
+static const struct of_device_id mmcc_msm8996_match_table[] = {
+	{ .compatible = "qcom,mmcc-msm8996" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mmcc_msm8996_match_table);
+
+static int mmcc_msm8996_probe(struct platform_device *pdev)
+{
+	struct clk *clk;
+	struct device *dev = &pdev->dev;
+	int i;
+	struct regmap *regmap;
+
+	regmap = qcom_cc_map(pdev, &mmcc_msm8996_desc);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	/* Disable the AHB DCD */
+	regmap_update_bits(regmap, 0x50d8, BIT(31), 0);
+	/* Disable the NoC FSM for mmss_mmagic_cfg_ahb_clk */
+	regmap_update_bits(regmap, 0x5054, BIT(15), 0);
+
+	for (i = 0; i < ARRAY_SIZE(mmcc_msm8996_hws); i++) {
+		clk = devm_clk_register(dev, mmcc_msm8996_hws[i]);
+		if (IS_ERR(clk))
+			return PTR_ERR(clk);
+	}
+
+	return qcom_cc_really_probe(pdev, &mmcc_msm8996_desc, regmap);
+}
+
+static struct platform_driver mmcc_msm8996_driver = {
+	.probe		= mmcc_msm8996_probe,
+	.driver		= {
+		.name	= "mmcc-msm8996",
+		.of_match_table = mmcc_msm8996_match_table,
+	},
+};
+module_platform_driver(mmcc_msm8996_driver);
+
+MODULE_DESCRIPTION("QCOM MMCC MSM8996 Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mmcc-msm8996");
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index b27edd6..80b9a37 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -10,6 +10,8 @@
 obj-y	+= clk-mmc-phase.o
 obj-$(CONFIG_RESET_CONTROLLER)	+= softrst.o
 
+obj-y	+= clk-rk3036.o
 obj-y	+= clk-rk3188.o
+obj-y	+= clk-rk3228.o
 obj-y	+= clk-rk3288.o
 obj-y	+= clk-rk3368.o
diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c
index 330870a..d07374f 100644
--- a/drivers/clk/rockchip/clk-cpu.c
+++ b/drivers/clk/rockchip/clk-cpu.c
@@ -242,8 +242,8 @@
 	struct clk *clk, *cclk;
 	int ret;
 
-	if (num_parents != 2) {
-		pr_err("%s: needs two parent clocks\n", __func__);
+	if (num_parents < 2) {
+		pr_err("%s: needs at least two parent clocks\n", __func__);
 		return ERR_PTR(-EINVAL);
 	}
 
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 4881eb8..b7e66c9 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -2,6 +2,9 @@
  * Copyright (c) 2014 MundoReader S.L.
  * Author: Heiko Stuebner <heiko@sntech.de>
  *
+ * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing@rock-chips.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -19,6 +22,7 @@
 #include <linux/delay.h>
 #include <linux/clk-provider.h>
 #include <linux/regmap.h>
+#include <linux/clk.h>
 #include "clk.h"
 
 #define PLL_MODE_MASK		0x3
@@ -108,6 +112,252 @@
 }
 
 /**
+ * PLL used in RK3036
+ */
+
+#define RK3036_PLLCON(i)			(i * 0x4)
+#define RK3036_PLLCON0_FBDIV_MASK		0xfff
+#define RK3036_PLLCON0_FBDIV_SHIFT		0
+#define RK3036_PLLCON0_POSTDIV1_MASK		0x7
+#define RK3036_PLLCON0_POSTDIV1_SHIFT		12
+#define RK3036_PLLCON1_REFDIV_MASK		0x3f
+#define RK3036_PLLCON1_REFDIV_SHIFT		0
+#define RK3036_PLLCON1_POSTDIV2_MASK		0x7
+#define RK3036_PLLCON1_POSTDIV2_SHIFT		6
+#define RK3036_PLLCON1_DSMPD_MASK		0x1
+#define RK3036_PLLCON1_DSMPD_SHIFT		12
+#define RK3036_PLLCON2_FRAC_MASK		0xffffff
+#define RK3036_PLLCON2_FRAC_SHIFT		0
+
+#define RK3036_PLLCON1_PWRDOWN			(1 << 13)
+
+static void rockchip_rk3036_pll_get_params(struct rockchip_clk_pll *pll,
+					struct rockchip_pll_rate_table *rate)
+{
+	u32 pllcon;
+
+	pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(0));
+	rate->fbdiv = ((pllcon >> RK3036_PLLCON0_FBDIV_SHIFT)
+				& RK3036_PLLCON0_FBDIV_MASK);
+	rate->postdiv1 = ((pllcon >> RK3036_PLLCON0_POSTDIV1_SHIFT)
+				& RK3036_PLLCON0_POSTDIV1_MASK);
+
+	pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(1));
+	rate->refdiv = ((pllcon >> RK3036_PLLCON1_REFDIV_SHIFT)
+				& RK3036_PLLCON1_REFDIV_MASK);
+	rate->postdiv2 = ((pllcon >> RK3036_PLLCON1_POSTDIV2_SHIFT)
+				& RK3036_PLLCON1_POSTDIV2_MASK);
+	rate->dsmpd = ((pllcon >> RK3036_PLLCON1_DSMPD_SHIFT)
+				& RK3036_PLLCON1_DSMPD_MASK);
+
+	pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(2));
+	rate->frac = ((pllcon >> RK3036_PLLCON2_FRAC_SHIFT)
+				& RK3036_PLLCON2_FRAC_MASK);
+}
+
+static unsigned long rockchip_rk3036_pll_recalc_rate(struct clk_hw *hw,
+						     unsigned long prate)
+{
+	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+	struct rockchip_pll_rate_table cur;
+	u64 rate64 = prate;
+
+	rockchip_rk3036_pll_get_params(pll, &cur);
+
+	rate64 *= cur.fbdiv;
+	do_div(rate64, cur.refdiv);
+
+	if (cur.dsmpd == 0) {
+		/* fractional mode */
+		u64 frac_rate64 = prate * cur.frac;
+
+		do_div(frac_rate64, cur.refdiv);
+		rate64 += frac_rate64 >> 24;
+	}
+
+	do_div(rate64, cur.postdiv1);
+	do_div(rate64, cur.postdiv2);
+
+	return (unsigned long)rate64;
+}
+
+static int rockchip_rk3036_pll_set_params(struct rockchip_clk_pll *pll,
+				const struct rockchip_pll_rate_table *rate)
+{
+	const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
+	struct clk_mux *pll_mux = &pll->pll_mux;
+	struct rockchip_pll_rate_table cur;
+	u32 pllcon;
+	int rate_change_remuxed = 0;
+	int cur_parent;
+	int ret;
+
+	pr_debug("%s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
+		__func__, rate->rate, rate->fbdiv, rate->postdiv1, rate->refdiv,
+		rate->postdiv2, rate->dsmpd, rate->frac);
+
+	rockchip_rk3036_pll_get_params(pll, &cur);
+	cur.rate = 0;
+
+	cur_parent = pll_mux_ops->get_parent(&pll_mux->hw);
+	if (cur_parent == PLL_MODE_NORM) {
+		pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
+		rate_change_remuxed = 1;
+	}
+
+	/* update pll values */
+	writel_relaxed(HIWORD_UPDATE(rate->fbdiv, RK3036_PLLCON0_FBDIV_MASK,
+					  RK3036_PLLCON0_FBDIV_SHIFT) |
+		       HIWORD_UPDATE(rate->postdiv1, RK3036_PLLCON0_POSTDIV1_MASK,
+					     RK3036_PLLCON0_POSTDIV1_SHIFT),
+		       pll->reg_base + RK3036_PLLCON(0));
+
+	writel_relaxed(HIWORD_UPDATE(rate->refdiv, RK3036_PLLCON1_REFDIV_MASK,
+						   RK3036_PLLCON1_REFDIV_SHIFT) |
+		       HIWORD_UPDATE(rate->postdiv2, RK3036_PLLCON1_POSTDIV2_MASK,
+						     RK3036_PLLCON1_POSTDIV2_SHIFT) |
+		       HIWORD_UPDATE(rate->dsmpd, RK3036_PLLCON1_DSMPD_MASK,
+						  RK3036_PLLCON1_DSMPD_SHIFT),
+		       pll->reg_base + RK3036_PLLCON(1));
+
+	/* GPLL CON2 is not HIWORD_MASK */
+	pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(2));
+	pllcon &= ~(RK3036_PLLCON2_FRAC_MASK << RK3036_PLLCON2_FRAC_SHIFT);
+	pllcon |= rate->frac << RK3036_PLLCON2_FRAC_SHIFT;
+	writel_relaxed(pllcon, pll->reg_base + RK3036_PLLCON(2));
+
+	/* wait for the pll to lock */
+	ret = rockchip_pll_wait_lock(pll);
+	if (ret) {
+		pr_warn("%s: pll update unsucessful, trying to restore old params\n",
+			__func__);
+		rockchip_rk3036_pll_set_params(pll, &cur);
+	}
+
+	if (rate_change_remuxed)
+		pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
+
+	return ret;
+}
+
+static int rockchip_rk3036_pll_set_rate(struct clk_hw *hw, unsigned long drate,
+					unsigned long prate)
+{
+	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+	const struct rockchip_pll_rate_table *rate;
+	unsigned long old_rate = rockchip_rk3036_pll_recalc_rate(hw, prate);
+	struct regmap *grf = rockchip_clk_get_grf();
+
+	if (IS_ERR(grf)) {
+		pr_debug("%s: grf regmap not available, aborting rate change\n",
+			 __func__);
+		return PTR_ERR(grf);
+	}
+
+	pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n",
+		 __func__, __clk_get_name(hw->clk), old_rate, drate, prate);
+
+	/* Get required rate settings from table */
+	rate = rockchip_get_pll_settings(pll, drate);
+	if (!rate) {
+		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+			drate, __clk_get_name(hw->clk));
+		return -EINVAL;
+	}
+
+	return rockchip_rk3036_pll_set_params(pll, rate);
+}
+
+static int rockchip_rk3036_pll_enable(struct clk_hw *hw)
+{
+	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+
+	writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0),
+	       pll->reg_base + RK3036_PLLCON(1));
+
+	return 0;
+}
+
+static void rockchip_rk3036_pll_disable(struct clk_hw *hw)
+{
+	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+
+	writel(HIWORD_UPDATE(RK3036_PLLCON1_PWRDOWN,
+			     RK3036_PLLCON1_PWRDOWN, 0),
+	       pll->reg_base + RK3036_PLLCON(1));
+}
+
+static int rockchip_rk3036_pll_is_enabled(struct clk_hw *hw)
+{
+	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+	u32 pllcon = readl(pll->reg_base + RK3036_PLLCON(1));
+
+	return !(pllcon & RK3036_PLLCON1_PWRDOWN);
+}
+
+static void rockchip_rk3036_pll_init(struct clk_hw *hw)
+{
+	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
+	const struct rockchip_pll_rate_table *rate;
+	struct rockchip_pll_rate_table cur;
+	unsigned long drate;
+
+	if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
+		return;
+
+	drate = clk_hw_get_rate(hw);
+	rate = rockchip_get_pll_settings(pll, drate);
+
+	/* when no rate setting for the current rate, rely on clk_set_rate */
+	if (!rate)
+		return;
+
+	rockchip_rk3036_pll_get_params(pll, &cur);
+
+	pr_debug("%s: pll %s@%lu: Hz\n", __func__, __clk_get_name(hw->clk),
+		 drate);
+	pr_debug("old - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
+		 cur.fbdiv, cur.postdiv1, cur.refdiv, cur.postdiv2,
+		 cur.dsmpd, cur.frac);
+	pr_debug("new - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
+		 rate->fbdiv, rate->postdiv1, rate->refdiv, rate->postdiv2,
+		 rate->dsmpd, rate->frac);
+
+	if (rate->fbdiv != cur.fbdiv || rate->postdiv1 != cur.postdiv1 ||
+		rate->refdiv != cur.refdiv || rate->postdiv2 != cur.postdiv2 ||
+		rate->dsmpd != cur.dsmpd || rate->frac != cur.frac) {
+		struct clk *parent = clk_get_parent(hw->clk);
+
+		if (!parent) {
+			pr_warn("%s: parent of %s not available\n",
+				__func__, __clk_get_name(hw->clk));
+			return;
+		}
+
+		pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n",
+			 __func__, __clk_get_name(hw->clk));
+		rockchip_rk3036_pll_set_params(pll, rate);
+	}
+}
+
+static const struct clk_ops rockchip_rk3036_pll_clk_norate_ops = {
+	.recalc_rate = rockchip_rk3036_pll_recalc_rate,
+	.enable = rockchip_rk3036_pll_enable,
+	.disable = rockchip_rk3036_pll_disable,
+	.is_enabled = rockchip_rk3036_pll_is_enabled,
+};
+
+static const struct clk_ops rockchip_rk3036_pll_clk_ops = {
+	.recalc_rate = rockchip_rk3036_pll_recalc_rate,
+	.round_rate = rockchip_pll_round_rate,
+	.set_rate = rockchip_rk3036_pll_set_rate,
+	.enable = rockchip_rk3036_pll_enable,
+	.disable = rockchip_rk3036_pll_disable,
+	.is_enabled = rockchip_rk3036_pll_is_enabled,
+	.init = rockchip_rk3036_pll_init,
+};
+
+/**
  * PLL used in RK3066, RK3188 and RK3288
  */
 
@@ -376,7 +626,7 @@
 	pll_mux->lock = lock;
 	pll_mux->hw.init = &init;
 
-	if (pll_type == pll_rk3066)
+	if (pll_type == pll_rk3036 || pll_type == pll_rk3066)
 		pll_mux->flags |= CLK_MUX_HIWORD_MASK;
 
 	/* the actual muxing is xin24m, pll-output, xin32k */
@@ -421,6 +671,12 @@
 	}
 
 	switch (pll_type) {
+	case pll_rk3036:
+		if (!pll->rate_table)
+			init.ops = &rockchip_rk3036_pll_clk_norate_ops;
+		else
+			init.ops = &rockchip_rk3036_pll_clk_ops;
+		break;
 	case pll_rk3066:
 		if (!pll->rate_table)
 			init.ops = &rockchip_rk3066_pll_clk_norate_ops;
diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c
new file mode 100644
index 0000000..ebce980
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rk3036.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2014 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+#include <dt-bindings/clock/rk3036-cru.h>
+#include "clk.h"
+
+#define RK3036_GRF_SOC_STATUS0	0x14c
+
+enum rk3036_plls {
+	apll, dpll, gpll,
+};
+
+static struct rockchip_pll_rate_table rk3036_pll_rates[] = {
+	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
+	RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
+	RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 984000000, 1, 82, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 960000000, 1, 80, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 936000000, 1, 78, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 912000000, 1, 76, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 900000000, 4, 300, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 888000000, 1, 74, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 864000000, 1, 72, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 840000000, 1, 70, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 816000000, 1, 68, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 800000000, 6, 400, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 700000000, 6, 350, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 696000000, 1, 58, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0),
+	RK3036_PLL_RATE( 594000000, 2, 99, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 504000000, 1, 63, 3, 1, 1, 0),
+	RK3036_PLL_RATE( 500000000, 6, 250, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 408000000, 1, 68, 2, 2, 1, 0),
+	RK3036_PLL_RATE( 312000000, 1, 52, 2, 2, 1, 0),
+	RK3036_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0),
+	RK3036_PLL_RATE(  96000000, 1, 64, 4, 4, 1, 0),
+	{ /* sentinel */ },
+};
+
+#define RK3036_DIV_CPU_MASK		0x1f
+#define RK3036_DIV_CPU_SHIFT		8
+
+#define RK3036_DIV_PERI_MASK		0xf
+#define RK3036_DIV_PERI_SHIFT		0
+#define RK3036_DIV_ACLK_MASK		0x7
+#define RK3036_DIV_ACLK_SHIFT		4
+#define RK3036_DIV_HCLK_MASK		0x3
+#define RK3036_DIV_HCLK_SHIFT		8
+#define RK3036_DIV_PCLK_MASK		0x7
+#define RK3036_DIV_PCLK_SHIFT		12
+
+#define RK3036_CLKSEL1(_core_periph_div)					\
+	{									\
+		.reg = RK2928_CLKSEL_CON(1),					\
+		.val = HIWORD_UPDATE(_core_periph_div, RK3036_DIV_PERI_MASK,	\
+				RK3036_DIV_PERI_SHIFT)				\
+	}
+
+#define RK3036_CPUCLK_RATE(_prate, _core_periph_div)			\
+	{								\
+		.prate = _prate,					\
+		.divs = {						\
+			RK3036_CLKSEL1(_core_periph_div),		\
+		},							\
+	}
+
+static struct rockchip_cpuclk_rate_table rk3036_cpuclk_rates[] __initdata = {
+	RK3036_CPUCLK_RATE(816000000, 4),
+	RK3036_CPUCLK_RATE(600000000, 4),
+	RK3036_CPUCLK_RATE(312000000, 4),
+};
+
+static const struct rockchip_cpuclk_reg_data rk3036_cpuclk_data = {
+	.core_reg = RK2928_CLKSEL_CON(0),
+	.div_core_shift = 0,
+	.div_core_mask = 0x1f,
+	.mux_core_shift = 7,
+};
+
+PNAME(mux_pll_p)		= { "xin24m", "xin24m" };
+
+PNAME(mux_armclk_p)		= { "apll", "gpll_armclk" };
+PNAME(mux_busclk_p)		= { "apll", "dpll_cpu", "gpll_cpu" };
+PNAME(mux_ddrphy_p)		= { "dpll_ddr", "gpll_ddr" };
+PNAME(mux_pll_src_3plls_p)	= { "apll", "dpll", "gpll" };
+PNAME(mux_timer_p)		= { "xin24m", "pclk_peri_src" };
+
+PNAME(mux_pll_src_apll_dpll_gpll_usb480m_p)	= { "apll", "dpll", "gpll" "usb480m" };
+
+PNAME(mux_mmc_src_p)	= { "apll", "dpll", "gpll", "xin24m" };
+PNAME(mux_i2s_pre_p)	= { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" };
+PNAME(mux_i2s_clkout_p)	= { "i2s_pre", "xin12m" };
+PNAME(mux_spdif_p)	= { "spdif_src", "spdif_frac", "xin12m" };
+PNAME(mux_uart0_p)	= { "uart0_src", "uart0_frac", "xin24m" };
+PNAME(mux_uart1_p)	= { "uart1_src", "uart1_frac", "xin24m" };
+PNAME(mux_uart2_p)	= { "uart2_src", "uart2_frac", "xin24m" };
+PNAME(mux_mac_p)	= { "mac_pll_src", "ext_gmac" };
+PNAME(mux_dclk_p)	= { "dclk_lcdc", "dclk_cru" };
+
+static struct rockchip_pll_clock rk3036_pll_clks[] __initdata = {
+	[apll] = PLL(pll_rk3036, PLL_APLL, "apll", mux_pll_p, 0, RK2928_PLL_CON(0),
+		     RK2928_MODE_CON, 0, 5, 0, rk3036_pll_rates),
+	[dpll] = PLL(pll_rk3036, PLL_DPLL, "dpll", mux_pll_p, 0, RK2928_PLL_CON(4),
+		     RK2928_MODE_CON, 4, 4, 0, NULL),
+	[gpll] = PLL(pll_rk3036, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(12),
+		     RK2928_MODE_CON, 12, 6, ROCKCHIP_PLL_SYNC_RATE, rk3036_pll_rates),
+};
+
+#define MFLAGS CLK_MUX_HIWORD_MASK
+#define DFLAGS CLK_DIVIDER_HIWORD_MASK
+#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
+
+static struct rockchip_clk_branch rk3036_uart0_fracmux __initdata =
+	MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(13), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3036_uart1_fracmux __initdata =
+	MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(14), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3036_uart2_fracmux __initdata =
+	MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(15), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3036_i2s_fracmux __initdata =
+	MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(3), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3036_spdif_fracmux __initdata =
+	MUX(SCLK_SPDIF, "sclk_spdif", mux_spdif_p, 0,
+			RK2928_CLKSEL_CON(5), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
+	/*
+	 * Clock-Architecture Diagram 1
+	 */
+
+	GATE(0, "gpll_armclk", "gpll", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(0), 6, GFLAGS),
+
+	/*
+	 * Clock-Architecture Diagram 2
+	 */
+
+	GATE(0, "dpll_ddr", "dpll", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(0), 2, GFLAGS),
+	GATE(0, "gpll_ddr", "gpll", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(0), 8, GFLAGS),
+	COMPOSITE_NOGATE(0, "ddrphy2x", mux_ddrphy_p, CLK_IGNORE_UNUSED,
+			RK2928_CLKSEL_CON(26), 8, 1, MFLAGS, 0, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO),
+
+	COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED,
+			RK2928_CLKSEL_CON(1), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK2928_CLKGATE_CON(0), 7, GFLAGS),
+	COMPOSITE_NOMUX(0, "aclk_core_pre", "armclk", CLK_IGNORE_UNUSED,
+			RK2928_CLKSEL_CON(1), 4, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK2928_CLKGATE_CON(0), 7, GFLAGS),
+
+	GATE(0, "dpll_cpu", "dpll", 0, RK2928_CLKGATE_CON(10), 8, GFLAGS),
+	GATE(0, "gpll_cpu", "gpll", 0, RK2928_CLKGATE_CON(0), 1, GFLAGS),
+	COMPOSITE_NOGATE(0, "aclk_cpu_src", mux_busclk_p, 0,
+			RK2928_CLKSEL_CON(0), 14, 2, MFLAGS, 8, 5, DFLAGS),
+	GATE(ACLK_CPU, "aclk_cpu", "aclk_cpu_src", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(0), 3, GFLAGS),
+	COMPOSITE_NOMUX(PCLK_CPU, "pclk_cpu", "aclk_cpu_src", CLK_IGNORE_UNUSED,
+			RK2928_CLKSEL_CON(1), 12, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK2928_CLKGATE_CON(0), 5, GFLAGS),
+	COMPOSITE_NOMUX(HCLK_CPU, "hclk_cpu", "aclk_cpu_src", CLK_IGNORE_UNUSED,
+			RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK2928_CLKGATE_CON(0), 4, GFLAGS),
+
+	COMPOSITE(0, "aclk_peri_src", mux_pll_src_3plls_p, 0,
+			RK2928_CLKSEL_CON(10), 14, 2, MFLAGS, 0, 5, DFLAGS,
+			RK2928_CLKGATE_CON(2), 0, GFLAGS),
+
+	GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", 0,
+			RK2928_CLKGATE_CON(2), 1, GFLAGS),
+	DIV(0, "pclk_peri_src", "aclk_peri_src", CLK_IGNORE_UNUSED,
+			RK2928_CLKSEL_CON(10), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO),
+	GATE(PCLK_PERI, "pclk_peri", "pclk_peri_src", 0,
+			RK2928_CLKGATE_CON(2), 3, GFLAGS),
+	DIV(0, "hclk_peri_src", "aclk_peri_src", CLK_IGNORE_UNUSED,
+			RK2928_CLKSEL_CON(10), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO),
+	GATE(HCLK_PERI, "hclk_peri", "hclk_peri_src", 0,
+			RK2928_CLKGATE_CON(2), 2, GFLAGS),
+
+	COMPOSITE_NODIV(SCLK_TIMER0, "sclk_timer0", mux_timer_p, CLK_IGNORE_UNUSED,
+			RK2928_CLKSEL_CON(2), 4, 1, DFLAGS,
+			RK2928_CLKGATE_CON(1), 0, GFLAGS),
+	COMPOSITE_NODIV(SCLK_TIMER1, "sclk_timer1", mux_timer_p, CLK_IGNORE_UNUSED,
+			RK2928_CLKSEL_CON(2), 5, 1, DFLAGS,
+			RK2928_CLKGATE_CON(1), 1, GFLAGS),
+	COMPOSITE_NODIV(SCLK_TIMER2, "sclk_timer2", mux_timer_p, CLK_IGNORE_UNUSED,
+			RK2928_CLKSEL_CON(2), 6, 1, DFLAGS,
+			RK2928_CLKGATE_CON(2), 4, GFLAGS),
+	COMPOSITE_NODIV(SCLK_TIMER3, "sclk_timer3", mux_timer_p, CLK_IGNORE_UNUSED,
+			RK2928_CLKSEL_CON(2), 7, 1, DFLAGS,
+			RK2928_CLKGATE_CON(2), 5, GFLAGS),
+
+	MUX(0, "uart_pll_clk", mux_pll_src_apll_dpll_gpll_usb480m_p, 0,
+			RK2928_CLKSEL_CON(13), 10, 2, MFLAGS),
+	COMPOSITE_NOMUX(0, "uart0_src", "uart_pll_clk", 0,
+			RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
+			RK2928_CLKGATE_CON(1), 8, GFLAGS),
+	COMPOSITE_NOMUX(0, "uart1_src", "uart_pll_clk", 0,
+			RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
+			RK2928_CLKGATE_CON(1), 8, GFLAGS),
+	COMPOSITE_NOMUX(0, "uart2_src", "uart_pll_clk", 0,
+			RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
+			RK2928_CLKGATE_CON(1), 8, GFLAGS),
+	COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(17), 0,
+			RK2928_CLKGATE_CON(1), 9, GFLAGS,
+			&rk3036_uart0_fracmux),
+	COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(18), 0,
+			RK2928_CLKGATE_CON(1), 11, GFLAGS,
+			&rk3036_uart1_fracmux),
+	COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(19), 0,
+			RK2928_CLKGATE_CON(1), 13, GFLAGS,
+			&rk3036_uart2_fracmux),
+
+	COMPOSITE(0, "aclk_vcodec", mux_pll_src_3plls_p, 0,
+			RK2928_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS,
+			RK2928_CLKGATE_CON(3), 11, GFLAGS),
+
+	COMPOSITE(0, "aclk_hvec", mux_pll_src_3plls_p, 0,
+			RK2928_CLKSEL_CON(20), 0, 2, MFLAGS, 2, 5, DFLAGS,
+			RK2928_CLKGATE_CON(10), 6, GFLAGS),
+
+	COMPOSITE(0, "aclk_disp1_pre", mux_pll_src_3plls_p, 0,
+			RK2928_CLKSEL_CON(31), 14, 2, MFLAGS, 8, 5, DFLAGS,
+			RK2928_CLKGATE_CON(1), 4, GFLAGS),
+	COMPOSITE(0, "hclk_disp_pre", mux_pll_src_3plls_p, 0,
+			RK2928_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS,
+			RK2928_CLKGATE_CON(0), 11, GFLAGS),
+	COMPOSITE(SCLK_LCDC, "dclk_lcdc", mux_pll_src_3plls_p, 0,
+			RK2928_CLKSEL_CON(28), 0, 2, MFLAGS, 8, 8, DFLAGS,
+			RK2928_CLKGATE_CON(3), 2, GFLAGS),
+
+	COMPOSITE_NODIV(0, "sclk_sdmmc_src", mux_mmc_src_p, 0,
+			RK2928_CLKSEL_CON(12), 8, 2, DFLAGS,
+			RK2928_CLKGATE_CON(2), 11, GFLAGS),
+	DIV(SCLK_SDMMC, "sclk_sdmmc", "sclk_sdmmc_src", 0,
+			RK2928_CLKSEL_CON(11), 0, 7, DFLAGS),
+
+	COMPOSITE_NODIV(0, "sclk_sdio_src", mux_mmc_src_p, 0,
+			RK2928_CLKSEL_CON(12), 10, 2, DFLAGS,
+			RK2928_CLKGATE_CON(2), 13, GFLAGS),
+	DIV(SCLK_SDIO, "sclk_sdio", "sclk_sdio_src", 0,
+			RK2928_CLKSEL_CON(11), 8, 7, DFLAGS),
+
+	COMPOSITE(SCLK_EMMC, "sclk_emmc", mux_mmc_src_p, 0,
+			RK2928_CLKSEL_CON(12), 12, 2, MFLAGS, 0, 7, DFLAGS,
+			RK2928_CLKGATE_CON(2), 14, GFLAGS),
+
+	MMC(SCLK_SDMMC_DRV,    "sdmmc_drv",    "sclk_sdmmc", RK3036_SDMMC_CON0, 1),
+	MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3036_SDMMC_CON1, 0),
+
+	MMC(SCLK_SDIO_DRV,     "sdio_drv",     "sclk_sdio",  RK3036_SDIO_CON0, 1),
+	MMC(SCLK_SDIO_SAMPLE,  "sdio_sample",  "sclk_sdio",  RK3036_SDIO_CON1, 0),
+
+	MMC(SCLK_EMMC_DRV,     "emmc_drv",     "sclk_emmc",  RK3036_EMMC_CON0,  1),
+	MMC(SCLK_EMMC_SAMPLE,  "emmc_sample",  "sclk_emmc",  RK3036_EMMC_CON1,  0),
+
+	COMPOSITE(0, "i2s_src", mux_pll_src_3plls_p, 0,
+			RK2928_CLKSEL_CON(3), 14, 2, MFLAGS, 0, 7, DFLAGS,
+			RK2928_CLKGATE_CON(0), 9, GFLAGS),
+	COMPOSITE_FRACMUX(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(7), 0,
+			RK2928_CLKGATE_CON(0), 10, GFLAGS,
+			&rk3036_i2s_fracmux),
+	COMPOSITE_NODIV(SCLK_I2S_OUT, "i2s_clkout", mux_i2s_clkout_p, 0,
+			RK2928_CLKSEL_CON(3), 12, 1, MFLAGS,
+			RK2928_CLKGATE_CON(0), 13, GFLAGS),
+	GATE(SCLK_I2S, "sclk_i2s", "i2s_pre", CLK_SET_RATE_PARENT,
+			RK2928_CLKGATE_CON(0), 14, GFLAGS),
+
+	COMPOSITE(0, "spdif_src", mux_pll_src_3plls_p, 0,
+			RK2928_CLKSEL_CON(5), 10, 2, MFLAGS, 0, 7, DFLAGS,
+			RK2928_CLKGATE_CON(2), 10, GFLAGS),
+	COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", 0,
+			RK2928_CLKSEL_CON(9), 0,
+			RK2928_CLKGATE_CON(2), 12, GFLAGS,
+			&rk3036_spdif_fracmux),
+
+	GATE(SCLK_OTGPHY0, "sclk_otgphy0", "xin12m", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(1), 5, GFLAGS),
+
+	COMPOSITE(SCLK_GPU, "sclk_gpu", mux_pll_src_3plls_p, 0,
+			RK2928_CLKSEL_CON(34), 8, 2, MFLAGS, 0, 5, DFLAGS,
+			RK2928_CLKGATE_CON(3), 13, GFLAGS),
+
+	COMPOSITE(SCLK_SPI, "sclk_spi", mux_pll_src_3plls_p, 0,
+			RK2928_CLKSEL_CON(25), 8, 2, MFLAGS, 0, 7, DFLAGS,
+			RK2928_CLKGATE_CON(2), 9, GFLAGS),
+
+	COMPOSITE(SCLK_NANDC, "sclk_nandc", mux_pll_src_3plls_p, 0,
+			RK2928_CLKSEL_CON(16), 8, 2, MFLAGS, 10, 5, DFLAGS,
+			RK2928_CLKGATE_CON(10), 4, GFLAGS),
+
+	COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_apll_dpll_gpll_usb480m_p, 0,
+			RK2928_CLKSEL_CON(16), 0, 2, MFLAGS, 2, 5, DFLAGS,
+			RK2928_CLKGATE_CON(10), 5, GFLAGS),
+
+	COMPOSITE_NOGATE(0, "mac_pll_src", mux_pll_src_3plls_p, 0,
+			RK2928_CLKSEL_CON(21), 0, 2, MFLAGS, 4, 5, DFLAGS),
+	MUX(SCLK_MACREF, "mac_clk_ref", mux_mac_p, CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(21), 3, 1, MFLAGS),
+
+	COMPOSITE_NOMUX(SCLK_MAC, "mac_clk", "mac_clk_ref", 0,
+			RK2928_CLKSEL_CON(21), 9, 5, DFLAGS,
+			RK2928_CLKGATE_CON(2), 6, GFLAGS),
+
+	MUX(SCLK_HDMI, "dclk_hdmi", mux_dclk_p, 0,
+			RK2928_CLKSEL_CON(31), 0, 1, MFLAGS),
+
+	/*
+	 * Clock-Architecture Diagram 3
+	 */
+
+	/* aclk_cpu gates */
+	GATE(0, "sclk_intmem", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 12, GFLAGS),
+	GATE(0, "aclk_strc_sys", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 10, GFLAGS),
+
+	/* hclk_cpu gates */
+	GATE(HCLK_ROM, "hclk_rom", "hclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 6, GFLAGS),
+
+	/* pclk_cpu gates */
+	GATE(PCLK_GRF, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 4, GFLAGS),
+	GATE(PCLK_DDRUPCTL, "pclk_ddrupctl", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 7, GFLAGS),
+	GATE(PCLK_ACODEC, "pclk_acodec", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 14, GFLAGS),
+	GATE(PCLK_HDMI, "pclk_hdmi", "pclk_cpu", 0, RK2928_CLKGATE_CON(3), 8, GFLAGS),
+
+	/* aclk_vio gates */
+	GATE(ACLK_VIO, "aclk_vio", "aclk_disp1_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(6), 13, GFLAGS),
+	GATE(ACLK_LCDC, "aclk_lcdc", "aclk_disp1_pre", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS),
+
+	GATE(HCLK_VIO_BUS, "hclk_vio_bus", "hclk_disp_pre", 0, RK2928_CLKGATE_CON(6), 12, GFLAGS),
+	GATE(HCLK_LCDC, "hclk_lcdc", "hclk_disp_pre", 0, RK2928_CLKGATE_CON(9), 5, GFLAGS),
+
+	/* hclk_video gates */
+	GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_disp_pre", 0, RK2928_CLKGATE_CON(3), 12, GFLAGS),
+
+	/* xin24m gates */
+	GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK2928_CLKGATE_CON(10), 0, GFLAGS),
+	GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0, RK2928_CLKGATE_CON(10), 1, GFLAGS),
+
+	/* aclk_peri gates */
+	GATE(0, "aclk_peri_axi_matrix", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 3, GFLAGS),
+	GATE(0, "aclk_cpu_peri", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 2, GFLAGS),
+	GATE(ACLK_DMAC2, "aclk_dmac2", "aclk_peri", 0, RK2928_CLKGATE_CON(5), 1, GFLAGS),
+	GATE(0, "aclk_peri_niu", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 15, GFLAGS),
+
+	/* hclk_peri gates */
+	GATE(0, "hclk_peri_matrix", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 0, GFLAGS),
+	GATE(0, "hclk_usb_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 13, GFLAGS),
+	GATE(0, "hclk_peri_arbi", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 14, GFLAGS),
+	GATE(HCLK_NANDC, "hclk_nandc", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 9, GFLAGS),
+	GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 10, GFLAGS),
+	GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 11, GFLAGS),
+	GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 0, GFLAGS),
+	GATE(HCLK_OTG0, "hclk_otg0", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 13, GFLAGS),
+	GATE(HCLK_OTG1, "hclk_otg1", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(7), 3, GFLAGS),
+	GATE(HCLK_I2S, "hclk_i2s", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS),
+	GATE(0, "hclk_sfc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 14, GFLAGS),
+	GATE(0, "hclk_mac", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 15, GFLAGS),
+
+	/* pclk_peri gates */
+	GATE(0, "pclk_peri_matrix", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 1, GFLAGS),
+	GATE(0, "pclk_efuse", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 2, GFLAGS),
+	GATE(PCLK_TIMER, "pclk_timer", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 7, GFLAGS),
+	GATE(PCLK_PWM, "pclk_pwm", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 10, GFLAGS),
+	GATE(PCLK_SPI, "pclk_spi", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 12, GFLAGS),
+	GATE(PCLK_WDT, "pclk_wdt", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 15, GFLAGS),
+	GATE(PCLK_UART0, "pclk_uart0", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 0, GFLAGS),
+	GATE(PCLK_UART1, "pclk_uart1", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 1, GFLAGS),
+	GATE(PCLK_UART2, "pclk_uart2", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 2, GFLAGS),
+	GATE(PCLK_I2C0, "pclk_i2c0", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 4, GFLAGS),
+	GATE(PCLK_I2C1, "pclk_i2c1", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 5, GFLAGS),
+	GATE(PCLK_I2C2, "pclk_i2c2", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 6, GFLAGS),
+	GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 9, GFLAGS),
+	GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 10, GFLAGS),
+	GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 11, GFLAGS),
+};
+
+static const char *const rk3036_critical_clocks[] __initconst = {
+	"aclk_cpu",
+	"aclk_peri",
+	"hclk_peri",
+	"pclk_peri",
+};
+
+static void __init rk3036_clk_init(struct device_node *np)
+{
+	void __iomem *reg_base;
+	struct clk *clk;
+
+	reg_base = of_iomap(np, 0);
+	if (!reg_base) {
+		pr_err("%s: could not map cru region\n", __func__);
+		return;
+	}
+
+	rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+
+	/* xin12m is created by an cru-internal divider */
+	clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2);
+	if (IS_ERR(clk))
+		pr_warn("%s: could not register clock xin12m: %ld\n",
+			__func__, PTR_ERR(clk));
+
+	clk = clk_register_fixed_factor(NULL, "usb480m", "xin24m", 0, 20, 1);
+	if (IS_ERR(clk))
+		pr_warn("%s: could not register clock usb480m: %ld\n",
+			__func__, PTR_ERR(clk));
+
+	clk = clk_register_fixed_factor(NULL, "ddrphy", "ddrphy2x", 0, 1, 2);
+	if (IS_ERR(clk))
+		pr_warn("%s: could not register clock ddrphy: %ld\n",
+			__func__, PTR_ERR(clk));
+
+	clk = clk_register_fixed_factor(NULL, "hclk_vcodec_pre",
+					"aclk_vcodec", 0, 1, 4);
+	if (IS_ERR(clk))
+		pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n",
+			__func__, PTR_ERR(clk));
+
+	clk = clk_register_fixed_factor(NULL, "sclk_macref_out",
+					"hclk_peri_src", 0, 1, 2);
+	if (IS_ERR(clk))
+		pr_warn("%s: could not register clock sclk_macref_out: %ld\n",
+			__func__, PTR_ERR(clk));
+
+	rockchip_clk_register_plls(rk3036_pll_clks,
+				   ARRAY_SIZE(rk3036_pll_clks),
+				   RK3036_GRF_SOC_STATUS0);
+	rockchip_clk_register_branches(rk3036_clk_branches,
+				  ARRAY_SIZE(rk3036_clk_branches));
+	rockchip_clk_protect_critical(rk3036_critical_clocks,
+				      ARRAY_SIZE(rk3036_critical_clocks));
+
+	rockchip_clk_register_armclk(ARMCLK, "armclk",
+			mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
+			&rk3036_cpuclk_data, rk3036_cpuclk_rates,
+			ARRAY_SIZE(rk3036_cpuclk_rates));
+
+	rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
+				  ROCKCHIP_SOFTRST_HIWORD_MASK);
+
+	rockchip_register_restart_notifier(RK2928_GLB_SRST_FST, NULL);
+}
+CLK_OF_DECLARE(rk3036_cru, "rockchip,rk3036-cru", rk3036_clk_init);
diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c
index abb4760..7f7444cb 100644
--- a/drivers/clk/rockchip/clk-rk3188.c
+++ b/drivers/clk/rockchip/clk-rk3188.c
@@ -247,6 +247,30 @@
 	{ /* sentinel */ },
 };
 
+static struct rockchip_clk_branch common_hsadc_out_fracmux __initdata =
+	MUX(0, "sclk_hsadc_out", mux_sclk_hsadc_p, 0,
+			RK2928_CLKSEL_CON(22), 4, 2, MFLAGS);
+
+static struct rockchip_clk_branch common_spdif_fracmux __initdata =
+	MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(5), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch common_uart0_fracmux __initdata =
+	MUX(SCLK_UART0, "sclk_uart0", mux_sclk_uart0_p, 0,
+			RK2928_CLKSEL_CON(13), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch common_uart1_fracmux __initdata =
+	MUX(SCLK_UART1, "sclk_uart1", mux_sclk_uart1_p, 0,
+			RK2928_CLKSEL_CON(14), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch common_uart2_fracmux __initdata =
+	MUX(SCLK_UART2, "sclk_uart2", mux_sclk_uart2_p, 0,
+			RK2928_CLKSEL_CON(15), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch common_uart3_fracmux __initdata =
+	MUX(SCLK_UART3, "sclk_uart3", mux_sclk_uart3_p, 0,
+			RK2928_CLKSEL_CON(16), 8, 2, MFLAGS);
+
 static struct rockchip_clk_branch common_clk_branches[] __initdata = {
 	/*
 	 * Clock-Architecture Diagram 2
@@ -335,11 +359,10 @@
 	COMPOSITE(0, "hsadc_src", mux_pll_src_gpll_cpll_p, 0,
 			RK2928_CLKSEL_CON(22), 0, 1, MFLAGS, 8, 8, DFLAGS,
 			RK2928_CLKGATE_CON(2), 6, GFLAGS),
-	COMPOSITE_FRAC(0, "hsadc_frac", "hsadc_src", 0,
+	COMPOSITE_FRACMUX(0, "hsadc_frac", "hsadc_src", 0,
 			RK2928_CLKSEL_CON(23), 0,
-			RK2928_CLKGATE_CON(2), 7, GFLAGS),
-	MUX(0, "sclk_hsadc_out", mux_sclk_hsadc_p, 0,
-			RK2928_CLKSEL_CON(22), 4, 2, MFLAGS),
+			RK2928_CLKGATE_CON(2), 7, GFLAGS,
+			&common_hsadc_out_fracmux),
 	INVERTER(SCLK_HSADC, "sclk_hsadc", "sclk_hsadc_out",
 			RK2928_CLKSEL_CON(22), 7, IFLAGS),
 
@@ -350,11 +373,10 @@
 	COMPOSITE_NOMUX(0, "spdif_pre", "i2s_src", 0,
 			RK2928_CLKSEL_CON(5), 0, 7, DFLAGS,
 			RK2928_CLKGATE_CON(0), 13, GFLAGS),
-	COMPOSITE_FRAC(0, "spdif_frac", "spdif_pre", CLK_SET_RATE_PARENT,
+	COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_pll", CLK_SET_RATE_PARENT,
 			RK2928_CLKSEL_CON(9), 0,
-			RK2928_CLKGATE_CON(0), 14, GFLAGS),
-	MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, CLK_SET_RATE_PARENT,
-			RK2928_CLKSEL_CON(5), 8, 2, MFLAGS),
+			RK2928_CLKGATE_CON(0), 14, GFLAGS,
+			&common_spdif_fracmux),
 
 	/*
 	 * Clock-Architecture Diagram 4
@@ -385,35 +407,31 @@
 	COMPOSITE_NOMUX(0, "uart0_pre", "uart_src", 0,
 			RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
 			RK2928_CLKGATE_CON(1), 8, GFLAGS),
-	COMPOSITE_FRAC(0, "uart0_frac", "uart0_pre", 0,
+	COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_pre", 0,
 			RK2928_CLKSEL_CON(17), 0,
-			RK2928_CLKGATE_CON(1), 9, GFLAGS),
-	MUX(SCLK_UART0, "sclk_uart0", mux_sclk_uart0_p, 0,
-			RK2928_CLKSEL_CON(13), 8, 2, MFLAGS),
+			RK2928_CLKGATE_CON(1), 9, GFLAGS,
+			&common_uart0_fracmux),
 	COMPOSITE_NOMUX(0, "uart1_pre", "uart_src", 0,
 			RK2928_CLKSEL_CON(14), 0, 7, DFLAGS,
 			RK2928_CLKGATE_CON(1), 10, GFLAGS),
-	COMPOSITE_FRAC(0, "uart1_frac", "uart1_pre", 0,
+	COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_pre", 0,
 			RK2928_CLKSEL_CON(18), 0,
-			RK2928_CLKGATE_CON(1), 11, GFLAGS),
-	MUX(SCLK_UART1, "sclk_uart1", mux_sclk_uart1_p, 0,
-			RK2928_CLKSEL_CON(14), 8, 2, MFLAGS),
+			RK2928_CLKGATE_CON(1), 11, GFLAGS,
+			&common_uart1_fracmux),
 	COMPOSITE_NOMUX(0, "uart2_pre", "uart_src", 0,
 			RK2928_CLKSEL_CON(15), 0, 7, DFLAGS,
 			RK2928_CLKGATE_CON(1), 12, GFLAGS),
-	COMPOSITE_FRAC(0, "uart2_frac", "uart2_pre", 0,
+	COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_pre", 0,
 			RK2928_CLKSEL_CON(19), 0,
-			RK2928_CLKGATE_CON(1), 13, GFLAGS),
-	MUX(SCLK_UART2, "sclk_uart2", mux_sclk_uart2_p, 0,
-			RK2928_CLKSEL_CON(15), 8, 2, MFLAGS),
+			RK2928_CLKGATE_CON(1), 13, GFLAGS,
+			&common_uart2_fracmux),
 	COMPOSITE_NOMUX(0, "uart3_pre", "uart_src", 0,
 			RK2928_CLKSEL_CON(16), 0, 7, DFLAGS,
 			RK2928_CLKGATE_CON(1), 14, GFLAGS),
-	COMPOSITE_FRAC(0, "uart3_frac", "uart3_pre", 0,
+	COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_pre", 0,
 			RK2928_CLKSEL_CON(20), 0,
-			RK2928_CLKGATE_CON(1), 15, GFLAGS),
-	MUX(SCLK_UART3, "sclk_uart3", mux_sclk_uart3_p, 0,
-			RK2928_CLKSEL_CON(16), 8, 2, MFLAGS),
+			RK2928_CLKGATE_CON(1), 15, GFLAGS,
+			&common_uart3_fracmux),
 
 	GATE(SCLK_JTAG, "jtag", "ext_jtag", 0, RK2928_CLKGATE_CON(1), 3, GFLAGS),
 
@@ -523,6 +541,18 @@
 	{ /* sentinel */ },
 };
 
+static struct rockchip_clk_branch rk3066a_i2s0_fracmux __initdata =
+	MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0,
+			RK2928_CLKSEL_CON(2), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3066a_i2s1_fracmux __initdata =
+	MUX(SCLK_I2S1, "sclk_i2s1", mux_sclk_i2s1_p, 0,
+			RK2928_CLKSEL_CON(3), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3066a_i2s2_fracmux __initdata =
+	MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, 0,
+			RK2928_CLKSEL_CON(4), 8, 2, MFLAGS);
+
 static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
 	DIVTBL(0, "aclk_cpu_pre", "armclk", 0,
 			RK2928_CLKSEL_CON(1), 0, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, div_aclk_cpu_t),
@@ -584,27 +614,24 @@
 	COMPOSITE_NOMUX(0, "i2s0_pre", "i2s_src", 0,
 			RK2928_CLKSEL_CON(2), 0, 7, DFLAGS,
 			RK2928_CLKGATE_CON(0), 7, GFLAGS),
-	COMPOSITE_FRAC(0, "i2s0_frac", "i2s0_pre", 0,
+	COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", 0,
 			RK2928_CLKSEL_CON(6), 0,
-			RK2928_CLKGATE_CON(0), 8, GFLAGS),
-	MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0,
-			RK2928_CLKSEL_CON(2), 8, 2, MFLAGS),
+			RK2928_CLKGATE_CON(0), 8, GFLAGS,
+			&rk3066a_i2s0_fracmux),
 	COMPOSITE_NOMUX(0, "i2s1_pre", "i2s_src", 0,
 			RK2928_CLKSEL_CON(3), 0, 7, DFLAGS,
 			RK2928_CLKGATE_CON(0), 9, GFLAGS),
-	COMPOSITE_FRAC(0, "i2s1_frac", "i2s1_pre", 0,
+	COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_pre", 0,
 			RK2928_CLKSEL_CON(7), 0,
-			RK2928_CLKGATE_CON(0), 10, GFLAGS),
-	MUX(SCLK_I2S1, "sclk_i2s1", mux_sclk_i2s1_p, 0,
-			RK2928_CLKSEL_CON(3), 8, 2, MFLAGS),
+			RK2928_CLKGATE_CON(0), 10, GFLAGS,
+			&rk3066a_i2s1_fracmux),
 	COMPOSITE_NOMUX(0, "i2s2_pre", "i2s_src", 0,
 			RK2928_CLKSEL_CON(4), 0, 7, DFLAGS,
 			RK2928_CLKGATE_CON(0), 11, GFLAGS),
-	COMPOSITE_FRAC(0, "i2s2_frac", "i2s2_pre", 0,
+	COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_pre", 0,
 			RK2928_CLKSEL_CON(8), 0,
-			RK2928_CLKGATE_CON(0), 12, GFLAGS),
-	MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, 0,
-			RK2928_CLKSEL_CON(4), 8, 2, MFLAGS),
+			RK2928_CLKGATE_CON(0), 12, GFLAGS,
+			&rk3066a_i2s2_fracmux),
 
 	GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS),
 	GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS),
@@ -638,6 +665,10 @@
 PNAME(mux_hsicphy_p)		= { "sclk_otgphy0", "sclk_otgphy1",
 				    "gpll", "cpll" };
 
+static struct rockchip_clk_branch rk3188_i2s0_fracmux __initdata =
+	MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0,
+			RK2928_CLKSEL_CON(3), 8, 2, MFLAGS);
+
 static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = {
 	COMPOSITE_NOMUX_DIVTBL(0, "aclk_core", "armclk", CLK_IGNORE_UNUSED,
 			RK2928_CLKSEL_CON(1), 3, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
@@ -691,11 +722,10 @@
 	COMPOSITE_NOMUX(0, "i2s0_pre", "i2s_src", 0,
 			RK2928_CLKSEL_CON(3), 0, 7, DFLAGS,
 			RK2928_CLKGATE_CON(0), 9, GFLAGS),
-	COMPOSITE_FRAC(0, "i2s0_frac", "i2s0_pre", 0,
+	COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", 0,
 			RK2928_CLKSEL_CON(7), 0,
-			RK2928_CLKGATE_CON(0), 10, GFLAGS),
-	MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0,
-			RK2928_CLKSEL_CON(3), 8, 2, MFLAGS),
+			RK2928_CLKGATE_CON(0), 10, GFLAGS,
+			&rk3188_i2s0_fracmux),
 
 	GATE(0, "hclk_imem0", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
 	GATE(0, "hclk_imem1", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 15, GFLAGS),
@@ -750,7 +780,7 @@
 	rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
 				  ROCKCHIP_SOFTRST_HIWORD_MASK);
 
-	rockchip_register_restart_notifier(RK2928_GLB_SRST_FST);
+	rockchip_register_restart_notifier(RK2928_GLB_SRST_FST, NULL);
 }
 
 static void __init rk3066a_clk_init(struct device_node *np)
diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c
new file mode 100644
index 0000000..981a502
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rk3228.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing@rock-chips.com>
+ *         Jeffy Chen <jeffy.chen@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+#include <dt-bindings/clock/rk3228-cru.h>
+#include "clk.h"
+
+#define RK3228_GRF_SOC_STATUS0	0x480
+
+enum rk3228_plls {
+	apll, dpll, cpll, gpll,
+};
+
+static struct rockchip_pll_rate_table rk3228_pll_rates[] = {
+	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
+	RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
+	RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
+	RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 984000000, 1, 82, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 960000000, 1, 80, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 936000000, 1, 78, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 912000000, 1, 76, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 900000000, 4, 300, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 888000000, 1, 74, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 864000000, 1, 72, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 840000000, 1, 70, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 816000000, 1, 68, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 800000000, 6, 400, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 700000000, 6, 350, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 696000000, 1, 58, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0),
+	RK3036_PLL_RATE( 594000000, 2, 99, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 504000000, 1, 63, 3, 1, 1, 0),
+	RK3036_PLL_RATE( 500000000, 6, 250, 2, 1, 1, 0),
+	RK3036_PLL_RATE( 408000000, 1, 68, 2, 2, 1, 0),
+	RK3036_PLL_RATE( 312000000, 1, 52, 2, 2, 1, 0),
+	RK3036_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0),
+	RK3036_PLL_RATE(  96000000, 1, 64, 4, 4, 1, 0),
+	{ /* sentinel */ },
+};
+
+#define RK3228_DIV_CPU_MASK		0x1f
+#define RK3228_DIV_CPU_SHIFT		8
+
+#define RK3228_DIV_PERI_MASK		0xf
+#define RK3228_DIV_PERI_SHIFT		0
+#define RK3228_DIV_ACLK_MASK		0x7
+#define RK3228_DIV_ACLK_SHIFT		4
+#define RK3228_DIV_HCLK_MASK		0x3
+#define RK3228_DIV_HCLK_SHIFT		8
+#define RK3228_DIV_PCLK_MASK		0x7
+#define RK3228_DIV_PCLK_SHIFT		12
+
+#define RK3228_CLKSEL1(_core_peri_div)					\
+	{									\
+		.reg = RK2928_CLKSEL_CON(1),					\
+		.val = HIWORD_UPDATE(_core_peri_div, RK3228_DIV_PERI_MASK,	\
+				RK3228_DIV_PERI_SHIFT)				\
+	}
+
+#define RK3228_CPUCLK_RATE(_prate, _core_peri_div)			\
+	{								\
+		.prate = _prate,					\
+		.divs = {						\
+			RK3228_CLKSEL1(_core_peri_div),		\
+		},							\
+	}
+
+static struct rockchip_cpuclk_rate_table rk3228_cpuclk_rates[] __initdata = {
+	RK3228_CPUCLK_RATE(816000000, 4),
+	RK3228_CPUCLK_RATE(600000000, 4),
+	RK3228_CPUCLK_RATE(312000000, 4),
+};
+
+static const struct rockchip_cpuclk_reg_data rk3228_cpuclk_data = {
+	.core_reg = RK2928_CLKSEL_CON(0),
+	.div_core_shift = 0,
+	.div_core_mask = 0x1f,
+	.mux_core_shift = 6,
+};
+
+PNAME(mux_pll_p)		= { "clk_24m", "xin24m" };
+
+PNAME(mux_ddrphy_p)		= { "dpll_ddr", "gpll_ddr", "apll_ddr" };
+PNAME(mux_armclk_p)		= { "apll_core", "gpll_core", "dpll_core" };
+PNAME(mux_usb480m_phy_p)	= { "usb480m_phy0", "usb480m_phy1" };
+PNAME(mux_usb480m_p)		= { "usb480m_phy", "xin24m" };
+PNAME(mux_hdmiphy_p)		= { "hdmiphy_phy", "xin24m" };
+PNAME(mux_aclk_cpu_src_p)	= { "cpll_aclk_cpu", "gpll_aclk_cpu", "hdmiphy_aclk_cpu" };
+
+PNAME(mux_pll_src_4plls_p)	= { "cpll", "gpll", "hdmiphy" "usb480m" };
+PNAME(mux_pll_src_3plls_p)	= { "cpll", "gpll", "hdmiphy" };
+PNAME(mux_pll_src_2plls_p)	= { "cpll", "gpll" };
+PNAME(mux_sclk_hdmi_cec_p)	= { "cpll", "gpll", "xin24m" };
+PNAME(mux_aclk_peri_src_p)	= { "cpll_peri", "gpll_peri", "hdmiphy_peri" };
+PNAME(mux_mmc_src_p)		= { "cpll", "gpll", "xin24m", "usb480m" };
+PNAME(mux_pll_src_cpll_gpll_usb480m_p)	= { "cpll", "gpll", "usb480m" };
+
+PNAME(mux_sclk_rga_p)		= { "gpll", "cpll", "sclk_rga_src" };
+
+PNAME(mux_sclk_vop_src_p)	= { "gpll_vop", "cpll_vop" };
+PNAME(mux_dclk_vop_p)		= { "hdmiphy", "sclk_vop_pre" };
+
+PNAME(mux_i2s0_p)		= { "i2s0_src", "i2s0_frac", "ext_i2s", "xin12m" };
+PNAME(mux_i2s1_pre_p)		= { "i2s1_src", "i2s1_frac", "ext_i2s", "xin12m" };
+PNAME(mux_i2s_out_p)		= { "i2s1_pre", "xin12m" };
+PNAME(mux_i2s2_p)		= { "i2s2_src", "i2s2_frac", "xin12m" };
+PNAME(mux_sclk_spdif_p)		= { "sclk_spdif_src", "spdif_frac", "xin12m" };
+
+PNAME(mux_aclk_gpu_pre_p)	= { "cpll_gpu", "gpll_gpu", "hdmiphy_gpu", "usb480m_gpu" };
+
+PNAME(mux_uart0_p)		= { "uart0_src", "uart0_frac", "xin24m" };
+PNAME(mux_uart1_p)		= { "uart1_src", "uart1_frac", "xin24m" };
+PNAME(mux_uart2_p)		= { "uart2_src", "uart2_frac", "xin24m" };
+
+PNAME(mux_sclk_macphy_50m_p)	= { "ext_gmac", "phy_50m_out" };
+PNAME(mux_sclk_gmac_pre_p)	= { "sclk_gmac_src", "sclk_macphy_50m" };
+PNAME(mux_sclk_macphy_p)	= { "sclk_gmac_src", "ext_gmac" };
+
+static struct rockchip_pll_clock rk3228_pll_clks[] __initdata = {
+	[apll] = PLL(pll_rk3036, PLL_APLL, "apll", mux_pll_p, 0, RK2928_PLL_CON(0),
+		     RK2928_MODE_CON, 0, 7, 0, rk3228_pll_rates),
+	[dpll] = PLL(pll_rk3036, PLL_DPLL, "dpll", mux_pll_p, 0, RK2928_PLL_CON(3),
+		     RK2928_MODE_CON, 4, 6, 0, NULL),
+	[cpll] = PLL(pll_rk3036, PLL_CPLL, "cpll", mux_pll_p, 0, RK2928_PLL_CON(6),
+		     RK2928_MODE_CON, 8, 8, 0, NULL),
+	[gpll] = PLL(pll_rk3036, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(9),
+		     RK2928_MODE_CON, 12, 9, ROCKCHIP_PLL_SYNC_RATE, rk3228_pll_rates),
+};
+
+#define MFLAGS CLK_MUX_HIWORD_MASK
+#define DFLAGS CLK_DIVIDER_HIWORD_MASK
+#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
+
+static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
+	/*
+	 * Clock-Architecture Diagram 1
+	 */
+
+	DIV(0, "clk_24m", "xin24m", CLK_IGNORE_UNUSED,
+			RK2928_CLKSEL_CON(4), 8, 5, DFLAGS),
+
+	/* PD_DDR */
+	GATE(0, "apll_ddr", "apll", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(0), 2, GFLAGS),
+	GATE(0, "dpll_ddr", "dpll", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(0), 2, GFLAGS),
+	GATE(0, "gpll_ddr", "gpll", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(0), 2, GFLAGS),
+	COMPOSITE(0, "ddrphy4x", mux_ddrphy_p, CLK_IGNORE_UNUSED,
+			RK2928_CLKSEL_CON(26), 8, 2, MFLAGS, 0, 3, DFLAGS | CLK_DIVIDER_POWER_OF_TWO,
+			RK2928_CLKGATE_CON(7), 1, GFLAGS),
+	GATE(0, "ddrc", "ddrphy_pre", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(8), 5, GFLAGS),
+	GATE(0, "ddrphy", "ddrphy_pre", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(7), 0, GFLAGS),
+
+	/* PD_CORE */
+	GATE(0, "dpll_core", "dpll", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(0), 6, GFLAGS),
+	GATE(0, "apll_core", "apll", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(0), 6, GFLAGS),
+	GATE(0, "gpll_core", "gpll", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(0), 6, GFLAGS),
+	COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED,
+			RK2928_CLKSEL_CON(1), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK2928_CLKGATE_CON(4), 1, GFLAGS),
+	COMPOSITE_NOMUX(0, "armcore", "armclk", CLK_IGNORE_UNUSED,
+			RK2928_CLKSEL_CON(1), 4, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
+			RK2928_CLKGATE_CON(4), 0, GFLAGS),
+
+	/* PD_MISC */
+	MUX(0, "hdmiphy", mux_hdmiphy_p, CLK_SET_RATE_PARENT,
+			RK2928_MISC_CON, 13, 1, MFLAGS),
+	MUX(0, "usb480m_phy", mux_usb480m_phy_p, CLK_SET_RATE_PARENT,
+			RK2928_MISC_CON, 14, 1, MFLAGS),
+	MUX(0, "usb480m", mux_usb480m_p, CLK_SET_RATE_PARENT,
+			RK2928_MISC_CON, 15, 1, MFLAGS),
+
+	/* PD_BUS */
+	GATE(0, "hdmiphy_aclk_cpu", "hdmiphy", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(0), 1, GFLAGS),
+	GATE(0, "gpll_aclk_cpu", "gpll", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(0), 1, GFLAGS),
+	GATE(0, "cpll_aclk_cpu", "cpll", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(0), 1, GFLAGS),
+	COMPOSITE_NOGATE(0, "aclk_cpu_src", mux_aclk_cpu_src_p, 0,
+			RK2928_CLKSEL_CON(0), 13, 2, MFLAGS, 8, 5, DFLAGS),
+	GATE(ARMCLK, "aclk_cpu", "aclk_cpu_src", 0,
+			RK2928_CLKGATE_CON(6), 0, GFLAGS),
+	COMPOSITE_NOMUX(0, "hclk_cpu", "aclk_cpu_src", 0,
+			RK2928_CLKSEL_CON(1), 8, 2, DFLAGS,
+			RK2928_CLKGATE_CON(6), 1, GFLAGS),
+	COMPOSITE_NOMUX(0, "pclk_bus_src", "aclk_cpu_src", 0,
+			RK2928_CLKSEL_CON(1), 12, 3, DFLAGS,
+			RK2928_CLKGATE_CON(6), 2, GFLAGS),
+	GATE(0, "pclk_cpu", "pclk_bus_src", 0,
+			RK2928_CLKGATE_CON(6), 3, GFLAGS),
+	GATE(0, "pclk_phy_pre", "pclk_bus_src", 0,
+			RK2928_CLKGATE_CON(6), 4, GFLAGS),
+	GATE(0, "pclk_ddr_pre", "pclk_bus_src", 0,
+			RK2928_CLKGATE_CON(6), 13, GFLAGS),
+
+	/* PD_VIDEO */
+	COMPOSITE(0, "aclk_vpu_pre", mux_pll_src_4plls_p, 0,
+			RK2928_CLKSEL_CON(32), 5, 2, MFLAGS, 0, 5, DFLAGS,
+			RK2928_CLKGATE_CON(3), 11, GFLAGS),
+	GATE(0, "hclk_vpu_src", "aclk_vpu_pre", 0,
+			RK2928_CLKGATE_CON(4), 4, GFLAGS),
+
+	COMPOSITE(0, "aclk_rkvdec_pre", mux_pll_src_4plls_p, 0,
+			RK2928_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 5, DFLAGS,
+			RK2928_CLKGATE_CON(3), 2, GFLAGS),
+	GATE(0, "hclk_rkvdec_src", "aclk_rkvdec_pre", 0,
+			RK2928_CLKGATE_CON(4), 5, GFLAGS),
+
+	COMPOSITE(0, "sclk_vdec_cabac", mux_pll_src_4plls_p, 0,
+			RK2928_CLKSEL_CON(28), 14, 2, MFLAGS, 8, 5, DFLAGS,
+			RK2928_CLKGATE_CON(3), 3, GFLAGS),
+
+	COMPOSITE(0, "sclk_vdec_core", mux_pll_src_4plls_p, 0,
+			RK2928_CLKSEL_CON(34), 13, 2, MFLAGS, 8, 5, DFLAGS,
+			RK2928_CLKGATE_CON(3), 4, GFLAGS),
+
+	/* PD_VIO */
+	COMPOSITE(0, "aclk_iep_pre", mux_pll_src_4plls_p, 0,
+			RK2928_CLKSEL_CON(31), 5, 2, MFLAGS, 0, 5, DFLAGS,
+			RK2928_CLKGATE_CON(3), 0, GFLAGS),
+	DIV(0, "hclk_vio_pre", "aclk_iep_pre", 0,
+			RK2928_CLKSEL_CON(2), 0, 5, DFLAGS),
+
+	COMPOSITE(0, "aclk_hdcp_pre", mux_pll_src_4plls_p, 0,
+			RK2928_CLKSEL_CON(31), 13, 2, MFLAGS, 8, 5, DFLAGS,
+			RK2928_CLKGATE_CON(1), 4, GFLAGS),
+
+	MUX(0, "sclk_rga_src", mux_pll_src_4plls_p, 0,
+			RK2928_CLKSEL_CON(33), 13, 2, MFLAGS),
+	COMPOSITE_NOMUX(0, "aclk_rga_pre", "sclk_rga_src", 0,
+			RK2928_CLKSEL_CON(33), 8, 5, DFLAGS,
+			RK2928_CLKGATE_CON(1), 2, GFLAGS),
+	COMPOSITE(0, "sclk_rga", mux_sclk_rga_p, 0,
+			RK2928_CLKSEL_CON(22), 5, 2, MFLAGS, 0, 5, DFLAGS,
+			RK2928_CLKGATE_CON(3), 6, GFLAGS),
+
+	COMPOSITE(0, "aclk_vop_pre", mux_pll_src_4plls_p, 0,
+			RK2928_CLKSEL_CON(33), 5, 2, MFLAGS, 0, 5, DFLAGS,
+			RK2928_CLKGATE_CON(1), 1, GFLAGS),
+
+	COMPOSITE(0, "sclk_hdcp", mux_pll_src_3plls_p, 0,
+			RK2928_CLKSEL_CON(23), 14, 2, MFLAGS, 8, 6, DFLAGS,
+			RK2928_CLKGATE_CON(3), 5, GFLAGS),
+
+	GATE(0, "sclk_hdmi_hdcp", "xin24m", 0,
+			RK2928_CLKGATE_CON(3), 7, GFLAGS),
+
+	COMPOSITE(0, "sclk_hdmi_cec", mux_sclk_hdmi_cec_p, 0,
+			RK2928_CLKSEL_CON(21), 14, 2, MFLAGS, 0, 14, DFLAGS,
+			RK2928_CLKGATE_CON(3), 8, GFLAGS),
+
+	/* PD_PERI */
+	GATE(0, "cpll_peri", "cpll", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(2), 0, GFLAGS),
+	GATE(0, "gpll_peri", "gpll", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(2), 0, GFLAGS),
+	GATE(0, "hdmiphy_peri", "hdmiphy", CLK_IGNORE_UNUSED,
+			RK2928_CLKGATE_CON(2), 0, GFLAGS),
+	COMPOSITE_NOGATE(0, "aclk_peri_src", mux_aclk_peri_src_p, 0,
+			RK2928_CLKSEL_CON(10), 10, 2, MFLAGS, 0, 5, DFLAGS),
+	COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_src", 0,
+			RK2928_CLKSEL_CON(10), 12, 3, DFLAGS,
+			RK2928_CLKGATE_CON(5), 2, GFLAGS),
+	COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_src", 0,
+			RK2928_CLKSEL_CON(10), 8, 2, DFLAGS,
+			RK2928_CLKGATE_CON(5), 1, GFLAGS),
+	GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", 0,
+			RK2928_CLKGATE_CON(5), 0, GFLAGS),
+
+	GATE(SCLK_TIMER0, "sclk_timer0", "xin24m", 0,
+			RK2928_CLKGATE_CON(6), 5, GFLAGS),
+	GATE(SCLK_TIMER1, "sclk_timer1", "xin24m", 0,
+			RK2928_CLKGATE_CON(6), 6, GFLAGS),
+	GATE(SCLK_TIMER2, "sclk_timer2", "xin24m", 0,
+			RK2928_CLKGATE_CON(6), 7, GFLAGS),
+	GATE(SCLK_TIMER3, "sclk_timer3", "xin24m", 0,
+			RK2928_CLKGATE_CON(6), 8, GFLAGS),
+	GATE(SCLK_TIMER4, "sclk_timer4", "xin24m", 0,
+			RK2928_CLKGATE_CON(6), 9, GFLAGS),
+	GATE(SCLK_TIMER5, "sclk_timer5", "xin24m", 0,
+			RK2928_CLKGATE_CON(6), 10, GFLAGS),
+
+	COMPOSITE(0, "sclk_crypto", mux_pll_src_2plls_p, 0,
+			RK2928_CLKSEL_CON(24), 5, 1, MFLAGS, 0, 5, DFLAGS,
+			RK2928_CLKGATE_CON(2), 7, GFLAGS),
+
+	COMPOSITE(0, "sclk_tsp", mux_pll_src_2plls_p, 0,
+			RK2928_CLKSEL_CON(22), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK2928_CLKGATE_CON(2), 6, GFLAGS),
+
+	GATE(0, "sclk_hsadc", "ext_hsadc", 0,
+			RK3288_CLKGATE_CON(10), 12, GFLAGS),
+
+	COMPOSITE(0, "sclk_wifi", mux_pll_src_cpll_gpll_usb480m_p, 0,
+			RK2928_CLKSEL_CON(23), 5, 2, MFLAGS, 0, 6, DFLAGS,
+			RK2928_CLKGATE_CON(2), 15, GFLAGS),
+
+	COMPOSITE(SCLK_SDMMC, "sclk_sdmmc0", mux_mmc_src_p, 0,
+			RK2928_CLKSEL_CON(11), 8, 2, MFLAGS, 0, 8, DFLAGS,
+			RK2928_CLKGATE_CON(2), 11, GFLAGS),
+
+	COMPOSITE_NODIV(0, "sclk_sdio_src", mux_mmc_src_p, 0,
+			RK2928_CLKSEL_CON(11), 10, 2, MFLAGS,
+			RK2928_CLKGATE_CON(2), 13, GFLAGS),
+	DIV(SCLK_SDIO, "sclk_sdio", "sclk_sdio_src", 0,
+			RK2928_CLKSEL_CON(12), 0, 8, DFLAGS),
+
+	COMPOSITE_NODIV(0, "sclk_emmc_src", mux_mmc_src_p, 0,
+			RK2928_CLKSEL_CON(11), 12, 2, MFLAGS,
+			RK2928_CLKGATE_CON(2), 14, GFLAGS),
+	DIV(SCLK_EMMC, "sclk_emmc", "sclk_emmc_src", 0,
+			RK2928_CLKSEL_CON(12), 8, 8, DFLAGS),
+
+	/*
+	 * Clock-Architecture Diagram 2
+	 */
+
+	GATE(0, "gpll_vop", "gpll", 0,
+			RK2928_CLKGATE_CON(3), 1, GFLAGS),
+	GATE(0, "cpll_vop", "cpll", 0,
+			RK2928_CLKGATE_CON(3), 1, GFLAGS),
+	MUX(0, "sclk_vop_src", mux_sclk_vop_src_p, 0,
+			RK2928_CLKSEL_CON(27), 0, 1, MFLAGS),
+	DIV(0, "dclk_hdmiphy", "sclk_vop_src", 0,
+			RK2928_CLKSEL_CON(29), 0, 3, DFLAGS),
+	DIV(0, "sclk_vop_pre", "sclk_vop_src", 0,
+			RK2928_CLKSEL_CON(27), 8, 8, DFLAGS),
+	MUX(0, "dclk_vop", mux_dclk_vop_p, 0,
+			RK2928_CLKSEL_CON(27), 1, 1, MFLAGS),
+
+	COMPOSITE(0, "i2s0_src", mux_pll_src_2plls_p, 0,
+			RK2928_CLKSEL_CON(9), 15, 1, MFLAGS, 0, 7, DFLAGS,
+			RK2928_CLKGATE_CON(0), 3, GFLAGS),
+	COMPOSITE_FRAC(0, "i2s0_frac", "i2s0_src", CLK_SET_RATE_PARENT,
+			RK3288_CLKSEL_CON(8), 0,
+			RK3288_CLKGATE_CON(0), 4, GFLAGS),
+	COMPOSITE_NODIV(SCLK_I2S0, "sclk_i2s0", mux_i2s0_p, 0,
+			RK2928_CLKSEL_CON(9), 8, 2, MFLAGS,
+			RK2928_CLKGATE_CON(0), 5, GFLAGS),
+
+	COMPOSITE(0, "i2s1_src", mux_pll_src_2plls_p, 0,
+			RK2928_CLKSEL_CON(3), 15, 1, MFLAGS, 0, 7, DFLAGS,
+			RK2928_CLKGATE_CON(0), 10, GFLAGS),
+	COMPOSITE_FRAC(0, "i2s1_frac", "i2s1_src", CLK_SET_RATE_PARENT,
+			RK3288_CLKSEL_CON(7), 0,
+			RK3288_CLKGATE_CON(0), 11, GFLAGS),
+	MUX(0, "i2s1_pre", mux_i2s1_pre_p, 0,
+			RK2928_CLKSEL_CON(3), 8, 2, MFLAGS),
+	GATE(SCLK_I2S1, "sclk_i2s1", "i2s1_pre", 0,
+			RK2928_CLKGATE_CON(0), 14, GFLAGS),
+	COMPOSITE_NODIV(SCLK_I2S_OUT, "i2s_out", mux_i2s_out_p, 0,
+			RK2928_CLKSEL_CON(3), 12, 1, MFLAGS,
+			RK2928_CLKGATE_CON(0), 13, GFLAGS),
+
+	COMPOSITE(0, "i2s2_src", mux_pll_src_2plls_p, 0,
+			RK2928_CLKSEL_CON(16), 15, 1, MFLAGS, 0, 7, DFLAGS,
+			RK2928_CLKGATE_CON(0), 7, GFLAGS),
+	COMPOSITE_FRAC(0, "i2s2_frac", "i2s2_src", CLK_SET_RATE_PARENT,
+			RK3288_CLKSEL_CON(30), 0,
+			RK3288_CLKGATE_CON(0), 8, GFLAGS),
+	COMPOSITE_NODIV(SCLK_I2S2, "sclk_i2s2", mux_i2s2_p, 0,
+			RK2928_CLKSEL_CON(16), 8, 2, MFLAGS,
+			RK2928_CLKGATE_CON(0), 9, GFLAGS),
+
+	COMPOSITE(0, "sclk_spdif_src", mux_pll_src_2plls_p, 0,
+			RK2928_CLKSEL_CON(6), 15, 1, MFLAGS, 0, 7, DFLAGS,
+			RK2928_CLKGATE_CON(2), 10, GFLAGS),
+	COMPOSITE_FRAC(0, "spdif_frac", "sclk_spdif_src", CLK_SET_RATE_PARENT,
+			RK3288_CLKSEL_CON(20), 0,
+			RK3288_CLKGATE_CON(2), 12, GFLAGS),
+	MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, 0,
+			RK2928_CLKSEL_CON(6), 8, 2, MFLAGS),
+
+	GATE(0, "jtag", "ext_jtag", 0,
+			RK2928_CLKGATE_CON(1), 3, GFLAGS),
+
+	GATE(0, "sclk_otgphy0", "xin24m", 0,
+			RK2928_CLKGATE_CON(1), 5, GFLAGS),
+	GATE(0, "sclk_otgphy1", "xin24m", 0,
+			RK2928_CLKGATE_CON(1), 6, GFLAGS),
+
+	COMPOSITE_NOMUX(0, "sclk_tsadc", "xin24m", 0,
+			RK2928_CLKSEL_CON(24), 6, 10, DFLAGS,
+			RK2928_CLKGATE_CON(2), 8, GFLAGS),
+
+	GATE(0, "cpll_gpu", "cpll", 0,
+			RK2928_CLKGATE_CON(3), 13, GFLAGS),
+	GATE(0, "gpll_gpu", "gpll", 0,
+			RK2928_CLKGATE_CON(3), 13, GFLAGS),
+	GATE(0, "hdmiphy_gpu", "hdmiphy", 0,
+			RK2928_CLKGATE_CON(3), 13, GFLAGS),
+	GATE(0, "usb480m_gpu", "usb480m", 0,
+			RK2928_CLKGATE_CON(3), 13, GFLAGS),
+	COMPOSITE_NOGATE(0, "aclk_gpu_pre", mux_aclk_gpu_pre_p, 0,
+			RK2928_CLKSEL_CON(34), 5, 2, MFLAGS, 0, 5, DFLAGS),
+
+	COMPOSITE(SCLK_SPI0, "sclk_spi0", mux_pll_src_2plls_p, 0,
+			RK2928_CLKSEL_CON(25), 8, 1, MFLAGS, 0, 7, DFLAGS,
+			RK2928_CLKGATE_CON(2), 9, GFLAGS),
+
+	/* PD_UART */
+	COMPOSITE(0, "uart0_src", mux_pll_src_cpll_gpll_usb480m_p, 0,
+			RK2928_CLKSEL_CON(13), 12, 2, MFLAGS, 0, 7, DFLAGS,
+			RK2928_CLKGATE_CON(1), 8, GFLAGS),
+	COMPOSITE(0, "uart1_src", mux_pll_src_cpll_gpll_usb480m_p, 0,
+			RK2928_CLKSEL_CON(14), 12, 2, MFLAGS, 0, 7, DFLAGS,
+			RK2928_CLKGATE_CON(1), 10, GFLAGS),
+	COMPOSITE(0, "uart2_src", mux_pll_src_cpll_gpll_usb480m_p,
+			0, RK2928_CLKSEL_CON(15), 12, 2,
+			MFLAGS, 0, 7, DFLAGS, RK2928_CLKGATE_CON(1), 12, GFLAGS),
+	COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(17), 0,
+			RK2928_CLKGATE_CON(1), 9, GFLAGS),
+	COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(18), 0,
+			RK2928_CLKGATE_CON(1), 11, GFLAGS),
+	COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(19), 0,
+			RK2928_CLKGATE_CON(1), 13, GFLAGS),
+	MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(13), 8, 2, MFLAGS),
+	MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(14), 8, 2, MFLAGS),
+	MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
+			RK2928_CLKSEL_CON(15), 8, 2, MFLAGS),
+
+	COMPOSITE(SCLK_NANDC, "sclk_nandc", mux_pll_src_2plls_p, 0,
+			RK2928_CLKSEL_CON(2), 14, 1, MFLAGS, 8, 5, DFLAGS,
+			RK2928_CLKGATE_CON(1), 0, GFLAGS),
+
+	COMPOSITE(0, "sclk_gmac_src", mux_pll_src_2plls_p, 0,
+			RK2928_CLKSEL_CON(5), 7, 1, MFLAGS, 0, 5, DFLAGS,
+			RK2928_CLKGATE_CON(1), 7, GFLAGS),
+	MUX(0, "sclk_macphy_50m", mux_sclk_macphy_50m_p, 0,
+			RK2928_CLKSEL_CON(29), 10, 1, MFLAGS),
+	MUX(0, "sclk_gmac_pre", mux_sclk_gmac_pre_p, 0,
+			RK2928_CLKSEL_CON(5), 5, 1, MFLAGS),
+	GATE(0, "sclk_mac_refout", "sclk_gmac_pre", 0,
+			RK2928_CLKGATE_CON(5), 4, GFLAGS),
+	GATE(0, "sclk_mac_ref", "sclk_gmac_pre", 0,
+			RK2928_CLKGATE_CON(5), 3, GFLAGS),
+	GATE(0, "sclk_mac_rx", "sclk_gmac_pre", 0,
+			RK2928_CLKGATE_CON(5), 5, GFLAGS),
+	GATE(0, "sclk_mac_tx", "sclk_gmac_pre", 0,
+			RK2928_CLKGATE_CON(5), 6, GFLAGS),
+	COMPOSITE(0, "sclk_macphy", mux_sclk_macphy_p, 0,
+			RK2928_CLKSEL_CON(29), 12, 1, MFLAGS, 8, 2, DFLAGS,
+			RK2928_CLKGATE_CON(5), 7, GFLAGS),
+	COMPOSITE(0, "sclk_gmac_out", mux_pll_src_2plls_p, 0,
+			RK2928_CLKSEL_CON(5), 15, 1, MFLAGS, 8, 5, DFLAGS,
+			RK2928_CLKGATE_CON(2), 2, GFLAGS),
+
+	/*
+	 * Clock-Architecture Diagram 3
+	 */
+
+	/* PD_VOP */
+	GATE(0, "aclk_rga", "aclk_rga_pre", 0, RK2928_CLKGATE_CON(13), 0, GFLAGS),
+	GATE(0, "aclk_rga_noc", "aclk_rga_pre", 0, RK2928_CLKGATE_CON(13), 11, GFLAGS),
+	GATE(0, "aclk_iep", "aclk_iep_pre", 0, RK2928_CLKGATE_CON(13), 2, GFLAGS),
+	GATE(0, "aclk_iep_noc", "aclk_iep_pre", 0, RK2928_CLKGATE_CON(13), 9, GFLAGS),
+
+	GATE(0, "aclk_vop", "aclk_vop_pre", 0, RK2928_CLKGATE_CON(13), 5, GFLAGS),
+	GATE(0, "aclk_vop_noc", "aclk_vop_pre", 0, RK2928_CLKGATE_CON(13), 12, GFLAGS),
+
+	GATE(0, "aclk_hdcp", "aclk_hdcp_pre", 0, RK2928_CLKGATE_CON(14), 10, GFLAGS),
+	GATE(0, "aclk_hdcp_noc", "aclk_hdcp_pre", 0, RK2928_CLKGATE_CON(13), 10, GFLAGS),
+
+	GATE(0, "hclk_rga", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 1, GFLAGS),
+	GATE(0, "hclk_iep", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 3, GFLAGS),
+	GATE(0, "hclk_vop", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 6, GFLAGS),
+	GATE(0, "hclk_vio_ahb_arbi", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 7, GFLAGS),
+	GATE(0, "hclk_vio_noc", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 8, GFLAGS),
+	GATE(0, "hclk_vop_noc", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 13, GFLAGS),
+	GATE(0, "hclk_vio_h2p", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 7, GFLAGS),
+	GATE(0, "hclk_hdcp_mmu", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 12, GFLAGS),
+	GATE(0, "pclk_hdmi_ctrl", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 6, GFLAGS),
+	GATE(0, "pclk_vio_h2p", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 8, GFLAGS),
+	GATE(0, "pclk_hdcp", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 11, GFLAGS),
+
+	/* PD_PERI */
+	GATE(0, "aclk_peri_noc", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(12), 0, GFLAGS),
+	GATE(0, "aclk_gmac", "aclk_peri", 0, RK2928_CLKGATE_CON(11), 4, GFLAGS),
+
+	GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 0, GFLAGS),
+	GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 1, GFLAGS),
+	GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 2, GFLAGS),
+	GATE(HCLK_NANDC, "hclk_nandc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 3, GFLAGS),
+	GATE(0, "hclk_host0", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 6, GFLAGS),
+	GATE(0, "hclk_host0_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 7, GFLAGS),
+	GATE(0, "hclk_host1", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 8, GFLAGS),
+	GATE(0, "hclk_host1_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 9, GFLAGS),
+	GATE(0, "hclk_host2", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 10, GFLAGS),
+	GATE(0, "hclk_otg", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 12, GFLAGS),
+	GATE(0, "hclk_otg_pmu", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 13, GFLAGS),
+	GATE(0, "hclk_host2_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 14, GFLAGS),
+	GATE(0, "hclk_peri_noc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(12), 1, GFLAGS),
+
+	GATE(0, "pclk_gmac", "pclk_peri", 0, RK2928_CLKGATE_CON(11), 5, GFLAGS),
+	GATE(0, "pclk_peri_noc", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(12), 2, GFLAGS),
+
+	/* PD_GPU */
+	GATE(0, "aclk_gpu", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(13), 14, GFLAGS),
+	GATE(0, "aclk_gpu_noc", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(13), 15, GFLAGS),
+
+	/* PD_BUS */
+	GATE(0, "sclk_initmem_mbist", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 1, GFLAGS),
+	GATE(0, "aclk_initmem", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 0, GFLAGS),
+	GATE(ACLK_DMAC, "aclk_dmac_bus", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 2, GFLAGS),
+	GATE(0, "aclk_bus_noc", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 1, GFLAGS),
+
+	GATE(0, "hclk_rom", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 3, GFLAGS),
+	GATE(0, "hclk_i2s0_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 7, GFLAGS),
+	GATE(0, "hclk_i2s1_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 8, GFLAGS),
+	GATE(0, "hclk_i2s2_2ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 9, GFLAGS),
+	GATE(0, "hclk_spdif_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 10, GFLAGS),
+	GATE(0, "hclk_tsp", "hclk_cpu", 0, RK2928_CLKGATE_CON(10), 11, GFLAGS),
+	GATE(0, "hclk_crypto_mst", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 11, GFLAGS),
+	GATE(0, "hclk_crypto_slv", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 12, GFLAGS),
+
+	GATE(0, "pclk_ddrupctl", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 4, GFLAGS),
+	GATE(0, "pclk_ddrmon", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 6, GFLAGS),
+	GATE(0, "pclk_msch_noc", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(10), 2, GFLAGS),
+
+	GATE(0, "pclk_efuse_1024", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS),
+	GATE(0, "pclk_efuse_256", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 14, GFLAGS),
+	GATE(PCLK_I2C0, "pclk_i2c0", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 15, GFLAGS),
+	GATE(PCLK_I2C1, "pclk_i2c1", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 0, GFLAGS),
+	GATE(PCLK_I2C2, "pclk_i2c2", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 1, GFLAGS),
+	GATE(PCLK_I2C3, "pclk_i2c3", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 2, GFLAGS),
+	GATE(PCLK_TIMER, "pclk_timer0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 4, GFLAGS),
+	GATE(0, "pclk_stimer", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 5, GFLAGS),
+	GATE(PCLK_SPI0, "pclk_spi0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS),
+	GATE(PCLK_PWM, "pclk_rk_pwm", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 7, GFLAGS),
+	GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 8, GFLAGS),
+	GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 9, GFLAGS),
+	GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 10, GFLAGS),
+	GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 11, GFLAGS),
+	GATE(PCLK_UART0, "pclk_uart0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 12, GFLAGS),
+	GATE(PCLK_UART1, "pclk_uart1", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 13, GFLAGS),
+	GATE(PCLK_UART2, "pclk_uart2", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 14, GFLAGS),
+	GATE(0, "pclk_tsadc", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 15, GFLAGS),
+	GATE(PCLK_GRF, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 0, GFLAGS),
+	GATE(0, "pclk_cru", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 1, GFLAGS),
+	GATE(0, "pclk_sgrf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 2, GFLAGS),
+	GATE(0, "pclk_sim", "pclk_cpu", 0, RK2928_CLKGATE_CON(10), 3, GFLAGS),
+
+	GATE(0, "pclk_ddrphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 3, GFLAGS),
+	GATE(0, "pclk_acodecphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 5, GFLAGS),
+	GATE(0, "pclk_hdmiphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 7, GFLAGS),
+	GATE(0, "pclk_vdacphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 8, GFLAGS),
+	GATE(0, "pclk_phy_noc", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 9, GFLAGS),
+
+	GATE(0, "aclk_vpu", "aclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 0, GFLAGS),
+	GATE(0, "aclk_vpu_noc", "aclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 4, GFLAGS),
+	GATE(0, "aclk_rkvdec", "aclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 2, GFLAGS),
+	GATE(0, "aclk_rkvdec_noc", "aclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 6, GFLAGS),
+	GATE(0, "hclk_vpu", "hclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 1, GFLAGS),
+	GATE(0, "hclk_vpu_noc", "hclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 5, GFLAGS),
+	GATE(0, "hclk_rkvdec", "hclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 3, GFLAGS),
+	GATE(0, "hclk_rkvdec_noc", "hclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 7, GFLAGS),
+
+	/* PD_MMC */
+	MMC(SCLK_SDMMC_DRV,    "sdmmc_drv",    "sclk_sdmmc", RK3228_SDMMC_CON0, 1),
+	MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3228_SDMMC_CON1, 1),
+
+	MMC(SCLK_SDIO_DRV,     "sdio_drv",     "sclk_sdio",  RK3228_SDIO_CON0,  1),
+	MMC(SCLK_SDIO_SAMPLE,  "sdio_sample",  "sclk_sdio",  RK3228_SDIO_CON1,  1),
+
+	MMC(SCLK_EMMC_DRV,     "emmc_drv",     "sclk_emmc",  RK3228_EMMC_CON0,  1),
+	MMC(SCLK_EMMC_SAMPLE,  "emmc_sample",  "sclk_emmc",  RK3228_EMMC_CON1,  1),
+};
+
+static const char *const rk3228_critical_clocks[] __initconst = {
+	"aclk_cpu",
+	"aclk_peri",
+	"hclk_peri",
+	"pclk_peri",
+};
+
+static void __init rk3228_clk_init(struct device_node *np)
+{
+	void __iomem *reg_base;
+	struct clk *clk;
+
+	reg_base = of_iomap(np, 0);
+	if (!reg_base) {
+		pr_err("%s: could not map cru region\n", __func__);
+		return;
+	}
+
+	rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+
+	/* xin12m is created by an cru-internal divider */
+	clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2);
+	if (IS_ERR(clk))
+		pr_warn("%s: could not register clock xin12m: %ld\n",
+				__func__, PTR_ERR(clk));
+
+	clk = clk_register_fixed_factor(NULL, "ddrphy_pre", "ddrphy4x", 0, 1, 4);
+	if (IS_ERR(clk))
+		pr_warn("%s: could not register clock ddrphy_pre: %ld\n",
+			__func__, PTR_ERR(clk));
+
+	clk = clk_register_fixed_factor(NULL, "hclk_vpu_pre",
+					"hclk_vpu_src", 0, 1, 4);
+	if (IS_ERR(clk))
+		pr_warn("%s: could not register clock hclk_vpu_pre: %ld\n",
+			__func__, PTR_ERR(clk));
+
+	clk = clk_register_fixed_factor(NULL, "hclk_rkvdec_pre",
+					"hclk_rkvdec_src", 0, 1, 4);
+	if (IS_ERR(clk))
+		pr_warn("%s: could not register clock hclk_rkvdec_pre: %ld\n",
+			__func__, PTR_ERR(clk));
+
+	rockchip_clk_register_plls(rk3228_pll_clks,
+				   ARRAY_SIZE(rk3228_pll_clks),
+				   RK3228_GRF_SOC_STATUS0);
+	rockchip_clk_register_branches(rk3228_clk_branches,
+				  ARRAY_SIZE(rk3228_clk_branches));
+	rockchip_clk_protect_critical(rk3228_critical_clocks,
+				      ARRAY_SIZE(rk3228_critical_clocks));
+
+	rockchip_clk_register_armclk(ARMCLK, "armclk",
+			mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
+			&rk3228_cpuclk_data, rk3228_cpuclk_rates,
+			ARRAY_SIZE(rk3228_cpuclk_rates));
+
+	rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
+				  ROCKCHIP_SOFTRST_HIWORD_MASK);
+
+	rockchip_register_restart_notifier(RK3228_GLB_SRST_FST, NULL);
+}
+CLK_OF_DECLARE(rk3228_cru, "rockchip,rk3228-cru", rk3228_clk_init);
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 9040878..984fc18 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -225,6 +225,38 @@
 #define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
 #define IFLAGS ROCKCHIP_INVERTER_HIWORD_MASK
 
+static struct rockchip_clk_branch rk3288_i2s_fracmux __initdata =
+	MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT,
+			RK3288_CLKSEL_CON(4), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3288_spdif_fracmux __initdata =
+	MUX(0, "spdif_mux", mux_spdif_p, CLK_SET_RATE_PARENT,
+			RK3288_CLKSEL_CON(5), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3288_spdif_8ch_fracmux __initdata =
+	MUX(0, "spdif_8ch_mux", mux_spdif_8ch_p, CLK_SET_RATE_PARENT,
+			RK3288_CLKSEL_CON(40), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3288_uart0_fracmux __initdata =
+	MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
+			RK3288_CLKSEL_CON(13), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3288_uart1_fracmux __initdata =
+	MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
+			RK3288_CLKSEL_CON(14), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3288_uart2_fracmux __initdata =
+	MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
+			RK3288_CLKSEL_CON(15), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3288_uart3_fracmux __initdata =
+	MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT,
+			RK3288_CLKSEL_CON(16), 8, 2, MFLAGS);
+
+static struct rockchip_clk_branch rk3288_uart4_fracmux __initdata =
+	MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT,
+			RK3288_CLKSEL_CON(3), 8, 2, MFLAGS);
+
 static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
 	/*
 	 * Clock-Architecture Diagram 1
@@ -295,7 +327,7 @@
 			RK3288_CLKGATE_CON(0), 4, GFLAGS),
 	GATE(0, "c2c_host", "aclk_cpu_src", 0,
 			RK3288_CLKGATE_CON(13), 8, GFLAGS),
-	COMPOSITE_NOMUX(0, "crypto", "aclk_cpu_pre", 0,
+	COMPOSITE_NOMUX(SCLK_CRYPTO, "crypto", "aclk_cpu_pre", 0,
 			RK3288_CLKSEL_CON(26), 6, 2, DFLAGS,
 			RK3288_CLKGATE_CON(5), 4, GFLAGS),
 	GATE(0, "aclk_bus_2pmu", "aclk_cpu_pre", CLK_IGNORE_UNUSED,
@@ -304,11 +336,10 @@
 	COMPOSITE(0, "i2s_src", mux_pll_src_cpll_gpll_p, 0,
 			RK3288_CLKSEL_CON(4), 15, 1, MFLAGS, 0, 7, DFLAGS,
 			RK3288_CLKGATE_CON(4), 1, GFLAGS),
-	COMPOSITE_FRAC(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT,
+	COMPOSITE_FRACMUX(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT,
 			RK3288_CLKSEL_CON(8), 0,
-			RK3288_CLKGATE_CON(4), 2, GFLAGS),
-	MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT,
-			RK3288_CLKSEL_CON(4), 8, 2, MFLAGS),
+			RK3288_CLKGATE_CON(4), 2, GFLAGS,
+			&rk3288_i2s_fracmux),
 	COMPOSITE_NODIV(SCLK_I2S0_OUT, "i2s0_clkout", mux_i2s_clkout_p, 0,
 			RK3288_CLKSEL_CON(4), 12, 1, MFLAGS,
 			RK3288_CLKGATE_CON(4), 0, GFLAGS),
@@ -317,23 +348,23 @@
 
 	MUX(0, "spdif_src", mux_pll_src_cpll_gpll_p, 0,
 			RK3288_CLKSEL_CON(5), 15, 1, MFLAGS),
-	COMPOSITE_NOMUX(0, "spdif_pre", "spdif_src", 0,
+	COMPOSITE_NOMUX(0, "spdif_pre", "spdif_src", CLK_SET_RATE_PARENT,
 			RK3288_CLKSEL_CON(5), 0, 7, DFLAGS,
 			RK3288_CLKGATE_CON(4), 4, GFLAGS),
-	COMPOSITE_FRAC(0, "spdif_frac", "spdif_src", 0,
+	COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", CLK_SET_RATE_PARENT,
 			RK3288_CLKSEL_CON(9), 0,
-			RK3288_CLKGATE_CON(4), 5, GFLAGS),
-	COMPOSITE_NODIV(SCLK_SPDIF, "sclk_spdif", mux_spdif_p, 0,
-			RK3288_CLKSEL_CON(5), 8, 2, MFLAGS,
+			RK3288_CLKGATE_CON(4), 5, GFLAGS,
+			&rk3288_spdif_fracmux),
+	GATE(SCLK_SPDIF, "sclk_spdif", "spdif_mux", CLK_SET_RATE_PARENT,
 			RK3288_CLKGATE_CON(4), 6, GFLAGS),
-	COMPOSITE_NOMUX(0, "spdif_8ch_pre", "spdif_src", 0,
+	COMPOSITE_NOMUX(0, "spdif_8ch_pre", "spdif_src", CLK_SET_RATE_PARENT,
 			RK3288_CLKSEL_CON(40), 0, 7, DFLAGS,
 			RK3288_CLKGATE_CON(4), 7, GFLAGS),
-	COMPOSITE_FRAC(0, "spdif_8ch_frac", "spdif_8ch_pre", 0,
+	COMPOSITE_FRACMUX(0, "spdif_8ch_frac", "spdif_8ch_pre", CLK_SET_RATE_PARENT,
 			RK3288_CLKSEL_CON(41), 0,
-			RK3288_CLKGATE_CON(4), 8, GFLAGS),
-	COMPOSITE_NODIV(SCLK_SPDIF8CH, "sclk_spdif_8ch", mux_spdif_8ch_p, 0,
-			RK3288_CLKSEL_CON(40), 8, 2, MFLAGS,
+			RK3288_CLKGATE_CON(4), 8, GFLAGS,
+			&rk3288_spdif_8ch_fracmux),
+	GATE(SCLK_SPDIF8CH, "sclk_spdif_8ch", "spdif_8ch_mux", CLK_SET_RATE_PARENT,
 			RK3288_CLKGATE_CON(4), 9, GFLAGS),
 
 	GATE(0, "sclk_acc_efuse", "xin24m", 0,
@@ -536,45 +567,40 @@
 	COMPOSITE(0, "uart0_src", mux_pll_src_cpll_gll_usb_npll_p, 0,
 			RK3288_CLKSEL_CON(13), 13, 2, MFLAGS, 0, 7, DFLAGS,
 			RK3288_CLKGATE_CON(1), 8, GFLAGS),
-	COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
+	COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
 			RK3288_CLKSEL_CON(17), 0,
-			RK3288_CLKGATE_CON(1), 9, GFLAGS),
-	MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
-			RK3288_CLKSEL_CON(13), 8, 2, MFLAGS),
+			RK3288_CLKGATE_CON(1), 9, GFLAGS,
+			&rk3288_uart0_fracmux),
 	MUX(0, "uart_src", mux_pll_src_cpll_gpll_p, 0,
 			RK3288_CLKSEL_CON(13), 15, 1, MFLAGS),
 	COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0,
 			RK3288_CLKSEL_CON(14), 0, 7, DFLAGS,
 			RK3288_CLKGATE_CON(1), 10, GFLAGS),
-	COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
+	COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
 			RK3288_CLKSEL_CON(18), 0,
-			RK3288_CLKGATE_CON(1), 11, GFLAGS),
-	MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
-			RK3288_CLKSEL_CON(14), 8, 2, MFLAGS),
+			RK3288_CLKGATE_CON(1), 11, GFLAGS,
+			&rk3288_uart1_fracmux),
 	COMPOSITE_NOMUX(0, "uart2_src", "uart_src", 0,
 			RK3288_CLKSEL_CON(15), 0, 7, DFLAGS,
 			RK3288_CLKGATE_CON(1), 12, GFLAGS),
-	COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
+	COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
 			RK3288_CLKSEL_CON(19), 0,
-			RK3288_CLKGATE_CON(1), 13, GFLAGS),
-	MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
-			RK3288_CLKSEL_CON(15), 8, 2, MFLAGS),
+			RK3288_CLKGATE_CON(1), 13, GFLAGS,
+			&rk3288_uart2_fracmux),
 	COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0,
 			RK3288_CLKSEL_CON(16), 0, 7, DFLAGS,
 			RK3288_CLKGATE_CON(1), 14, GFLAGS),
-	COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT,
+	COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT,
 			RK3288_CLKSEL_CON(20), 0,
-			RK3288_CLKGATE_CON(1), 15, GFLAGS),
-	MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT,
-			RK3288_CLKSEL_CON(16), 8, 2, MFLAGS),
+			RK3288_CLKGATE_CON(1), 15, GFLAGS,
+			&rk3288_uart3_fracmux),
 	COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0,
 			RK3288_CLKSEL_CON(3), 0, 7, DFLAGS,
 			RK3288_CLKGATE_CON(2), 12, GFLAGS),
-	COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT,
+	COMPOSITE_FRACMUX(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT,
 			RK3288_CLKSEL_CON(7), 0,
-			RK3288_CLKGATE_CON(2), 13, GFLAGS),
-	MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT,
-			RK3288_CLKSEL_CON(3), 8, 2, MFLAGS),
+			RK3288_CLKGATE_CON(2), 13, GFLAGS,
+			&rk3288_uart4_fracmux),
 
 	COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0,
 			RK3288_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS,
@@ -644,10 +670,10 @@
 	GATE(PCLK_PUBL0, "pclk_publ0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 15, GFLAGS),
 	GATE(PCLK_DDRUPCTL1, "pclk_ddrupctl1", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 0, GFLAGS),
 	GATE(PCLK_PUBL1, "pclk_publ1", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 1, GFLAGS),
-	GATE(0, "pclk_efuse_1024", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 2, GFLAGS),
+	GATE(PCLK_EFUSE1024, "pclk_efuse_1024", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 2, GFLAGS),
 	GATE(PCLK_TZPC, "pclk_tzpc", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 3, GFLAGS),
 	GATE(PCLK_UART2, "pclk_uart2", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 9, GFLAGS),
-	GATE(0, "pclk_efuse_256", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 10, GFLAGS),
+	GATE(PCLK_EFUSE256, "pclk_efuse_256", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 10, GFLAGS),
 	GATE(PCLK_RKPWM, "pclk_rkpwm", "pclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(11), 11, GFLAGS),
 
 	/* ddrctrl [DDR Controller PHY clock] gates */
@@ -709,7 +735,7 @@
 	GATE(SCLK_LCDC_PWM1, "sclk_lcdc_pwm1", "xin24m", 0, RK3288_CLKGATE_CON(13), 11, GFLAGS),
 	GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK3288_CLKGATE_CON(5), 9, GFLAGS),
 	GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0, RK3288_CLKGATE_CON(5), 10, GFLAGS),
-	GATE(0, "sclk_mipidsi_24m", "xin24m", 0, RK3288_CLKGATE_CON(5), 15, GFLAGS),
+	GATE(SCLK_MIPIDSI_24M, "sclk_mipidsi_24m", "xin24m", 0, RK3288_CLKGATE_CON(5), 15, GFLAGS),
 
 	/* sclk_gpu gates */
 	GATE(ACLK_GPU, "aclk_gpu", "sclk_gpu", 0, RK3288_CLKGATE_CON(18), 0, GFLAGS),
@@ -783,10 +809,10 @@
 	"pclk_pd_pmu",
 };
 
-#ifdef CONFIG_PM_SLEEP
 static void __iomem *rk3288_cru_base;
 
-/* Some CRU registers will be reset in maskrom when the system
+/*
+ * Some CRU registers will be reset in maskrom when the system
  * wakes up from fastboot.
  * So save them before suspend, restore them after resume.
  */
@@ -840,33 +866,27 @@
 	}
 }
 
+static void rk3288_clk_shutdown(void)
+{
+	writel_relaxed(0xf3030000, rk3288_cru_base + RK3288_MODE_CON);
+}
+
 static struct syscore_ops rk3288_clk_syscore_ops = {
 	.suspend = rk3288_clk_suspend,
 	.resume = rk3288_clk_resume,
 };
 
-static void rk3288_clk_sleep_init(void __iomem *reg_base)
-{
-	rk3288_cru_base = reg_base;
-	register_syscore_ops(&rk3288_clk_syscore_ops);
-}
-
-#else /* CONFIG_PM_SLEEP */
-static void rk3288_clk_sleep_init(void __iomem *reg_base) {}
-#endif
-
 static void __init rk3288_clk_init(struct device_node *np)
 {
-	void __iomem *reg_base;
 	struct clk *clk;
 
-	reg_base = of_iomap(np, 0);
-	if (!reg_base) {
+	rk3288_cru_base = of_iomap(np, 0);
+	if (!rk3288_cru_base) {
 		pr_err("%s: could not map cru region\n", __func__);
 		return;
 	}
 
-	rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
+	rockchip_clk_init(np, rk3288_cru_base, CLK_NR_CLKS);
 
 	/* xin12m is created by an cru-internal divider */
 	clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2);
@@ -907,10 +927,12 @@
 			&rk3288_cpuclk_data, rk3288_cpuclk_rates,
 			ARRAY_SIZE(rk3288_cpuclk_rates));
 
-	rockchip_register_softrst(np, 12, reg_base + RK3288_SOFTRST_CON(0),
+	rockchip_register_softrst(np, 12,
+				  rk3288_cru_base + RK3288_SOFTRST_CON(0),
 				  ROCKCHIP_SOFTRST_HIWORD_MASK);
 
-	rockchip_register_restart_notifier(RK3288_GLB_SRST_FST);
-	rk3288_clk_sleep_init(reg_base);
+	rockchip_register_restart_notifier(RK3288_GLB_SRST_FST,
+					   rk3288_clk_shutdown);
+	register_syscore_ops(&rk3288_clk_syscore_ops);
 }
 CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init);
diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c
index 7e6b783..be0ede5 100644
--- a/drivers/clk/rockchip/clk-rk3368.c
+++ b/drivers/clk/rockchip/clk-rk3368.c
@@ -184,13 +184,13 @@
 
 #define RK3368_CLKSEL0(_offs, _aclkm)					\
 	{								\
-		.reg = RK3288_CLKSEL_CON(0 + _offs),			\
+		.reg = RK3368_CLKSEL_CON(0 + _offs),			\
 		.val = HIWORD_UPDATE(_aclkm, RK3368_DIV_ACLKM_MASK,	\
 				RK3368_DIV_ACLKM_SHIFT),		\
 	}
 #define RK3368_CLKSEL1(_offs, _atclk, _pdbg)				\
 	{								\
-		.reg = RK3288_CLKSEL_CON(1 + _offs),			\
+		.reg = RK3368_CLKSEL_CON(1 + _offs),			\
 		.val = HIWORD_UPDATE(_atclk, RK3368_DIV_ATCLK_MASK,	\
 				RK3368_DIV_ATCLK_SHIFT) |		\
 		       HIWORD_UPDATE(_pdbg, RK3368_DIV_PCLK_DBG_MASK,	\
@@ -819,6 +819,13 @@
 };
 
 static const char *const rk3368_critical_clocks[] __initconst = {
+	"aclk_bus",
+	"aclk_peri",
+	/*
+	 * pwm1 supplies vdd_logic on a lot of boards, is currently unhandled
+	 * but needs to stay enabled there (including its parents) at all times.
+	 */
+	"pclk_pwm1",
 	"pclk_pd_pmu",
 };
 
@@ -882,6 +889,6 @@
 	rockchip_register_softrst(np, 15, reg_base + RK3368_SOFTRST_CON(0),
 				  ROCKCHIP_SOFTRST_HIWORD_MASK);
 
-	rockchip_register_restart_notifier(RK3368_GLB_SRST_FST);
+	rockchip_register_restart_notifier(RK3368_GLB_SRST_FST, NULL);
 }
 CLK_OF_DECLARE(rk3368_cru, "rockchip,rk3368-cru", rk3368_clk_init);
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
index be6c7fd..d9a0b5d 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -102,22 +102,82 @@
 	return clk;
 }
 
+struct rockchip_clk_frac {
+	struct notifier_block			clk_nb;
+	struct clk_fractional_divider		div;
+	struct clk_gate				gate;
+
+	struct clk_mux				mux;
+	const struct clk_ops			*mux_ops;
+	int					mux_frac_idx;
+
+	bool					rate_change_remuxed;
+	int					rate_change_idx;
+};
+
+#define to_rockchip_clk_frac_nb(nb) \
+			container_of(nb, struct rockchip_clk_frac, clk_nb)
+
+static int rockchip_clk_frac_notifier_cb(struct notifier_block *nb,
+					 unsigned long event, void *data)
+{
+	struct clk_notifier_data *ndata = data;
+	struct rockchip_clk_frac *frac = to_rockchip_clk_frac_nb(nb);
+	struct clk_mux *frac_mux = &frac->mux;
+	int ret = 0;
+
+	pr_debug("%s: event %lu, old_rate %lu, new_rate: %lu\n",
+		 __func__, event, ndata->old_rate, ndata->new_rate);
+	if (event == PRE_RATE_CHANGE) {
+		frac->rate_change_idx = frac->mux_ops->get_parent(&frac_mux->hw);
+		if (frac->rate_change_idx != frac->mux_frac_idx) {
+			frac->mux_ops->set_parent(&frac_mux->hw, frac->mux_frac_idx);
+			frac->rate_change_remuxed = 1;
+		}
+	} else if (event == POST_RATE_CHANGE) {
+		/*
+		 * The POST_RATE_CHANGE notifier runs directly after the
+		 * divider clock is set in clk_change_rate, so we'll have
+		 * remuxed back to the original parent before clk_change_rate
+		 * reaches the mux itself.
+		 */
+		if (frac->rate_change_remuxed) {
+			frac->mux_ops->set_parent(&frac_mux->hw, frac->rate_change_idx);
+			frac->rate_change_remuxed = 0;
+		}
+	}
+
+	return notifier_from_errno(ret);
+}
+
 static struct clk *rockchip_clk_register_frac_branch(const char *name,
 		const char *const *parent_names, u8 num_parents,
 		void __iomem *base, int muxdiv_offset, u8 div_flags,
 		int gate_offset, u8 gate_shift, u8 gate_flags,
-		unsigned long flags, spinlock_t *lock)
+		unsigned long flags, struct rockchip_clk_branch *child,
+		spinlock_t *lock)
 {
+	struct rockchip_clk_frac *frac;
 	struct clk *clk;
 	struct clk_gate *gate = NULL;
 	struct clk_fractional_divider *div = NULL;
 	const struct clk_ops *div_ops = NULL, *gate_ops = NULL;
 
-	if (gate_offset >= 0) {
-		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
-		if (!gate)
-			return ERR_PTR(-ENOMEM);
+	if (muxdiv_offset < 0)
+		return ERR_PTR(-EINVAL);
 
+	if (child && child->branch_type != branch_mux) {
+		pr_err("%s: fractional child clock for %s can only be a mux\n",
+		       __func__, name);
+		return ERR_PTR(-EINVAL);
+	}
+
+	frac = kzalloc(sizeof(*frac), GFP_KERNEL);
+	if (!frac)
+		return ERR_PTR(-ENOMEM);
+
+	if (gate_offset >= 0) {
+		gate = &frac->gate;
 		gate->flags = gate_flags;
 		gate->reg = base + gate_offset;
 		gate->bit_idx = gate_shift;
@@ -125,13 +185,7 @@
 		gate_ops = &clk_gate_ops;
 	}
 
-	if (muxdiv_offset < 0)
-		return ERR_PTR(-EINVAL);
-
-	div = kzalloc(sizeof(*div), GFP_KERNEL);
-	if (!div)
-		return ERR_PTR(-ENOMEM);
-
+	div = &frac->div;
 	div->flags = div_flags;
 	div->reg = base + muxdiv_offset;
 	div->mshift = 16;
@@ -147,7 +201,61 @@
 				     NULL, NULL,
 				     &div->hw, div_ops,
 				     gate ? &gate->hw : NULL, gate_ops,
-				     flags);
+				     flags | CLK_SET_RATE_UNGATE);
+	if (IS_ERR(clk)) {
+		kfree(frac);
+		return clk;
+	}
+
+	if (child) {
+		struct clk_mux *frac_mux = &frac->mux;
+		struct clk_init_data init;
+		struct clk *mux_clk;
+		int i, ret;
+
+		frac->mux_frac_idx = -1;
+		for (i = 0; i < child->num_parents; i++) {
+			if (!strcmp(name, child->parent_names[i])) {
+				pr_debug("%s: found fractional parent in mux at pos %d\n",
+					 __func__, i);
+				frac->mux_frac_idx = i;
+				break;
+			}
+		}
+
+		frac->mux_ops = &clk_mux_ops;
+		frac->clk_nb.notifier_call = rockchip_clk_frac_notifier_cb;
+
+		frac_mux->reg = base + child->muxdiv_offset;
+		frac_mux->shift = child->mux_shift;
+		frac_mux->mask = BIT(child->mux_width) - 1;
+		frac_mux->flags = child->mux_flags;
+		frac_mux->lock = lock;
+		frac_mux->hw.init = &init;
+
+		init.name = child->name;
+		init.flags = child->flags | CLK_SET_RATE_PARENT;
+		init.ops = frac->mux_ops;
+		init.parent_names = child->parent_names;
+		init.num_parents = child->num_parents;
+
+		mux_clk = clk_register(NULL, &frac_mux->hw);
+		if (IS_ERR(mux_clk))
+			return clk;
+
+		rockchip_clk_add_lookup(mux_clk, child->id);
+
+		/* notifier on the fraction divider to catch rate changes */
+		if (frac->mux_frac_idx >= 0) {
+			ret = clk_notifier_register(clk, &frac->clk_nb);
+			if (ret)
+				pr_err("%s: failed to register clock notifier for %s\n",
+						__func__, name);
+		} else {
+			pr_warn("%s: could not find %s as parent of %s, rate changes may not work\n",
+				__func__, name, child->name);
+		}
+	}
 
 	return clk;
 }
@@ -251,7 +359,8 @@
 				list->parent_names, list->num_parents,
 				reg_base, list->muxdiv_offset, list->div_flags,
 				list->gate_offset, list->gate_shift,
-				list->gate_flags, flags, &clk_lock);
+				list->gate_flags, flags, list->child,
+				&clk_lock);
 			break;
 		case branch_gate:
 			flags |= CLK_SET_RATE_PARENT;
@@ -341,9 +450,13 @@
 }
 
 static unsigned int reg_restart;
+static void (*cb_restart)(void);
 static int rockchip_restart_notify(struct notifier_block *this,
 				   unsigned long mode, void *cmd)
 {
+	if (cb_restart)
+		cb_restart();
+
 	writel(0xfdb9, reg_base + reg_restart);
 	return NOTIFY_DONE;
 }
@@ -353,11 +466,12 @@
 	.priority = 128,
 };
 
-void __init rockchip_register_restart_notifier(unsigned int reg)
+void __init rockchip_register_restart_notifier(unsigned int reg, void (*cb)(void))
 {
 	int ret;
 
 	reg_restart = reg;
+	cb_restart = cb;
 	ret = register_restart_handler(&rockchip_restart_handler);
 	if (ret)
 		pr_err("%s: cannot register restart handler, %d\n",
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index dc8ecb2..ff8bd23 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -2,6 +2,9 @@
  * Copyright (c) 2014 MundoReader S.L.
  * Author: Heiko Stuebner <heiko@sntech.de>
  *
+ * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing@rock-chips.com>
+ *
  * based on
  *
  * samsung/clk.h
@@ -30,7 +33,7 @@
 #define HIWORD_UPDATE(val, mask, shift) \
 		((val) << (shift) | (mask) << ((shift) + 16))
 
-/* register positions shared by RK2928, RK3066 and RK3188 */
+/* register positions shared by RK2928, RK3036, RK3066, RK3188 and RK3228 */
 #define RK2928_PLL_CON(x)		((x) * 0x4)
 #define RK2928_MODE_CON		0x40
 #define RK2928_CLKSEL_CON(x)	((x) * 0x4 + 0x44)
@@ -40,6 +43,22 @@
 #define RK2928_SOFTRST_CON(x)	((x) * 0x4 + 0x110)
 #define RK2928_MISC_CON		0x134
 
+#define RK3036_SDMMC_CON0		0x144
+#define RK3036_SDMMC_CON1		0x148
+#define RK3036_SDIO_CON0		0x14c
+#define RK3036_SDIO_CON1		0x150
+#define RK3036_EMMC_CON0		0x154
+#define RK3036_EMMC_CON1		0x158
+
+#define RK3228_GLB_SRST_FST		0x1f0
+#define RK3228_GLB_SRST_SND		0x1f4
+#define RK3228_SDMMC_CON0		0x1c0
+#define RK3228_SDMMC_CON1		0x1c4
+#define RK3228_SDIO_CON0		0x1c8
+#define RK3228_SDIO_CON1		0x1cc
+#define RK3228_EMMC_CON0		0x1d8
+#define RK3228_EMMC_CON1		0x1dc
+
 #define RK3288_PLL_CON(x)		RK2928_PLL_CON(x)
 #define RK3288_MODE_CON			0x50
 #define RK3288_CLKSEL_CON(x)		((x) * 0x4 + 0x60)
@@ -74,9 +93,22 @@
 #define RK3368_EMMC_CON1		0x41c
 
 enum rockchip_pll_type {
+	pll_rk3036,
 	pll_rk3066,
 };
 
+#define RK3036_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1,	\
+			_postdiv2, _dsmpd, _frac)		\
+{								\
+	.rate	= _rate##U,					\
+	.fbdiv = _fbdiv,					\
+	.postdiv1 = _postdiv1,					\
+	.refdiv = _refdiv,					\
+	.postdiv2 = _postdiv2,					\
+	.dsmpd = _dsmpd,					\
+	.frac = _frac,						\
+}
+
 #define RK3066_PLL_RATE(_rate, _nr, _nf, _no)	\
 {						\
 	.rate	= _rate##U,			\
@@ -101,6 +133,13 @@
 	unsigned int nf;
 	unsigned int no;
 	unsigned int nb;
+	/* for RK3036 */
+	unsigned int fbdiv;
+	unsigned int postdiv1;
+	unsigned int refdiv;
+	unsigned int postdiv2;
+	unsigned int dsmpd;
+	unsigned int frac;
 };
 
 /**
@@ -235,6 +274,7 @@
 	int				gate_offset;
 	u8				gate_shift;
 	u8				gate_flags;
+	struct rockchip_clk_branch	*child;
 };
 
 #define COMPOSITE(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw,\
@@ -369,6 +409,24 @@
 		.gate_flags	= gf,				\
 	}
 
+#define COMPOSITE_FRACMUX(_id, cname, pname, f, mo, df, go, gs, gf, ch) \
+	{							\
+		.id		= _id,				\
+		.branch_type	= branch_fraction_divider,	\
+		.name		= cname,			\
+		.parent_names	= (const char *[]){ pname },	\
+		.num_parents	= 1,				\
+		.flags		= f,				\
+		.muxdiv_offset	= mo,				\
+		.div_shift	= 16,				\
+		.div_width	= 16,				\
+		.div_flags	= df,				\
+		.gate_offset	= go,				\
+		.gate_shift	= gs,				\
+		.gate_flags	= gf,				\
+		.child		= ch,				\
+	}
+
 #define MUX(_id, cname, pnames, f, o, s, w, mf)			\
 	{							\
 		.id		= _id,				\
@@ -464,7 +522,7 @@
 			const struct rockchip_cpuclk_rate_table *rates,
 			int nrates);
 void rockchip_clk_protect_critical(const char *const clocks[], int nclocks);
-void rockchip_register_restart_notifier(unsigned int reg);
+void rockchip_register_restart_notifier(unsigned int reg, void (*cb)(void));
 
 #define ROCKCHIP_SOFTRST_HIWORD_MASK	BIT(0)
 
diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c
index 2fe37f7..813003d 100644
--- a/drivers/clk/samsung/clk-cpu.c
+++ b/drivers/clk/samsung/clk-cpu.c
@@ -148,6 +148,7 @@
 	unsigned long alt_prate = clk_get_rate(cpuclk->alt_parent);
 	unsigned long alt_div = 0, alt_div_mask = DIV_MASK;
 	unsigned long div0, div1 = 0, mux_reg;
+	unsigned long flags;
 
 	/* find out the divider values to use for clock data */
 	while ((cfg_data->prate * 1000) != ndata->new_rate) {
@@ -156,7 +157,7 @@
 		cfg_data++;
 	}
 
-	spin_lock(cpuclk->lock);
+	spin_lock_irqsave(cpuclk->lock, flags);
 
 	/*
 	 * For the selected PLL clock frequency, get the pre-defined divider
@@ -212,7 +213,7 @@
 				DIV_MASK_ALL);
 	}
 
-	spin_unlock(cpuclk->lock);
+	spin_unlock_irqrestore(cpuclk->lock, flags);
 	return 0;
 }
 
@@ -223,6 +224,7 @@
 	const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg;
 	unsigned long div = 0, div_mask = DIV_MASK;
 	unsigned long mux_reg;
+	unsigned long flags;
 
 	/* find out the divider values to use for clock data */
 	if (cpuclk->flags & CLK_CPU_NEEDS_DEBUG_ALT_DIV) {
@@ -233,7 +235,7 @@
 		}
 	}
 
-	spin_lock(cpuclk->lock);
+	spin_lock_irqsave(cpuclk->lock, flags);
 
 	/* select mout_apll as the alternate parent */
 	mux_reg = readl(base + E4210_SRC_CPU);
@@ -246,7 +248,7 @@
 	}
 
 	exynos_set_safe_div(base, div, div_mask);
-	spin_unlock(cpuclk->lock);
+	spin_unlock_irqrestore(cpuclk->lock, flags);
 	return 0;
 }
 
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index 389af3c..d048ded 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -18,6 +18,7 @@
 #include <linux/syscore_ops.h>
 
 #include "clk.h"
+#include "clk-cpu.h"
 
 #define APLL_LOCK		0x0
 #define APLL_CON0		0x100
@@ -616,9 +617,11 @@
 	MUX(0, "mout_mspll_kfc", mout_mspll_cpu_p, SRC_TOP7, 8, 2),
 	MUX(0, "mout_mspll_cpu", mout_mspll_cpu_p, SRC_TOP7, 12, 2),
 
-	MUX(0, "mout_apll", mout_apll_p, SRC_CPU, 0, 1),
+	MUX_F(0, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
+	      CLK_SET_RATE_PARENT | CLK_RECALC_NEW_RATES, 0),
 	MUX(0, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1),
-	MUX(0, "mout_kpll", mout_kpll_p, SRC_KFC, 0, 1),
+	MUX_F(0, "mout_kpll", mout_kpll_p, SRC_KFC, 0, 1,
+	      CLK_SET_RATE_PARENT | CLK_RECALC_NEW_RATES, 0),
 	MUX(0, "mout_kfc", mout_kfc_p, SRC_KFC, 16, 1),
 
 	MUX(0, "mout_aclk200", mout_group1_p, SRC_TOP0, 8, 2),
@@ -677,8 +680,8 @@
 			SRC_TOP5, 20, 1),
 	MUX(CLK_MOUT_USER_ACLK300_DISP1, "mout_user_aclk300_disp1",
 			mout_user_aclk300_disp1_p, SRC_TOP5, 24, 1),
-	MUX(0, "mout_user_aclk300_gscl", mout_user_aclk300_gscl_p,
-			SRC_TOP5, 28, 1),
+	MUX(CLK_MOUT_USER_ACLK300_GSCL, "mout_user_aclk300_gscl",
+			mout_user_aclk300_gscl_p, SRC_TOP5, 28, 1),
 
 	MUX(0, "mout_sclk_mpll", mout_mpll_p, SRC_TOP6, 0, 1),
 	MUX(CLK_MOUT_VPLL, "mout_sclk_vpll", mout_vpll_p, SRC_TOP6, 4, 1),
@@ -729,8 +732,8 @@
 			SRC_TOP12, 20, 1),
 	MUX(CLK_MOUT_SW_ACLK300, "mout_sw_aclk300_disp1",
 			mout_sw_aclk300_disp1_p, SRC_TOP12, 24, 1),
-	MUX(0, "mout_sw_aclk300_gscl", mout_sw_aclk300_gscl_p,
-			SRC_TOP12, 28, 1),
+	MUX(CLK_MOUT_SW_ACLK300_GSCL, "mout_sw_aclk300_gscl",
+			mout_sw_aclk300_gscl_p, SRC_TOP12, 28, 1),
 
 	/* DISP1 Block */
 	MUX(0, "mout_mipi1", mout_group2_p, SRC_DISP10, 16, 3),
@@ -926,7 +929,7 @@
 			GATE_BUS_TOP, 13, 0, 0),
 	GATE(0, "aclk166", "mout_user_aclk166",
 			GATE_BUS_TOP, 14, CLK_IGNORE_UNUSED, 0),
-	GATE(0, "aclk333", "mout_aclk333",
+	GATE(0, "aclk333", "mout_user_aclk333",
 			GATE_BUS_TOP, 15, CLK_IGNORE_UNUSED, 0),
 	GATE(0, "aclk400_isp", "mout_user_aclk400_isp",
 			GATE_BUS_TOP, 16, 0, 0),
@@ -1246,6 +1249,74 @@
 		KPLL_CON0, NULL),
 };
 
+#define E5420_EGL_DIV0(apll, pclk_dbg, atb, cpud)			\
+		((((apll) << 24) | ((pclk_dbg) << 20) | ((atb) << 16) |	\
+		 ((cpud) << 4)))
+
+static const struct exynos_cpuclk_cfg_data exynos5420_eglclk_d[] __initconst = {
+	{ 1800000, E5420_EGL_DIV0(3, 7, 7, 4), },
+	{ 1700000, E5420_EGL_DIV0(3, 7, 7, 3), },
+	{ 1600000, E5420_EGL_DIV0(3, 7, 7, 3), },
+	{ 1500000, E5420_EGL_DIV0(3, 7, 7, 3), },
+	{ 1400000, E5420_EGL_DIV0(3, 7, 7, 3), },
+	{ 1300000, E5420_EGL_DIV0(3, 7, 7, 2), },
+	{ 1200000, E5420_EGL_DIV0(3, 7, 7, 2), },
+	{ 1100000, E5420_EGL_DIV0(3, 7, 7, 2), },
+	{ 1000000, E5420_EGL_DIV0(3, 6, 6, 2), },
+	{  900000, E5420_EGL_DIV0(3, 6, 6, 2), },
+	{  800000, E5420_EGL_DIV0(3, 5, 5, 2), },
+	{  700000, E5420_EGL_DIV0(3, 5, 5, 2), },
+	{  600000, E5420_EGL_DIV0(3, 4, 4, 2), },
+	{  500000, E5420_EGL_DIV0(3, 3, 3, 2), },
+	{  400000, E5420_EGL_DIV0(3, 3, 3, 2), },
+	{  300000, E5420_EGL_DIV0(3, 3, 3, 2), },
+	{  200000, E5420_EGL_DIV0(3, 3, 3, 2), },
+	{  0 },
+};
+
+static const struct exynos_cpuclk_cfg_data exynos5800_eglclk_d[] __initconst = {
+	{ 2000000, E5420_EGL_DIV0(3, 7, 7, 4), },
+	{ 1900000, E5420_EGL_DIV0(3, 7, 7, 4), },
+	{ 1800000, E5420_EGL_DIV0(3, 7, 7, 4), },
+	{ 1700000, E5420_EGL_DIV0(3, 7, 7, 3), },
+	{ 1600000, E5420_EGL_DIV0(3, 7, 7, 3), },
+	{ 1500000, E5420_EGL_DIV0(3, 7, 7, 3), },
+	{ 1400000, E5420_EGL_DIV0(3, 7, 7, 3), },
+	{ 1300000, E5420_EGL_DIV0(3, 7, 7, 2), },
+	{ 1200000, E5420_EGL_DIV0(3, 7, 7, 2), },
+	{ 1100000, E5420_EGL_DIV0(3, 7, 7, 2), },
+	{ 1000000, E5420_EGL_DIV0(3, 7, 6, 2), },
+	{  900000, E5420_EGL_DIV0(3, 7, 6, 2), },
+	{  800000, E5420_EGL_DIV0(3, 7, 5, 2), },
+	{  700000, E5420_EGL_DIV0(3, 7, 5, 2), },
+	{  600000, E5420_EGL_DIV0(3, 7, 4, 2), },
+	{  500000, E5420_EGL_DIV0(3, 7, 3, 2), },
+	{  400000, E5420_EGL_DIV0(3, 7, 3, 2), },
+	{  300000, E5420_EGL_DIV0(3, 7, 3, 2), },
+	{  200000, E5420_EGL_DIV0(3, 7, 3, 2), },
+	{  0 },
+};
+
+#define E5420_KFC_DIV(kpll, pclk, aclk)					\
+		((((kpll) << 24) | ((pclk) << 20) | ((aclk) << 4)))
+
+static const struct exynos_cpuclk_cfg_data exynos5420_kfcclk_d[] __initconst = {
+	{ 1400000, E5420_KFC_DIV(3, 5, 3), }, /* for Exynos5800 */
+	{ 1300000, E5420_KFC_DIV(3, 5, 2), },
+	{ 1200000, E5420_KFC_DIV(3, 5, 2), },
+	{ 1100000, E5420_KFC_DIV(3, 5, 2), },
+	{ 1000000, E5420_KFC_DIV(3, 5, 2), },
+	{  900000, E5420_KFC_DIV(3, 5, 2), },
+	{  800000, E5420_KFC_DIV(3, 5, 2), },
+	{  700000, E5420_KFC_DIV(3, 4, 2), },
+	{  600000, E5420_KFC_DIV(3, 4, 2), },
+	{  500000, E5420_KFC_DIV(3, 4, 2), },
+	{  400000, E5420_KFC_DIV(3, 3, 2), },
+	{  300000, E5420_KFC_DIV(3, 3, 2), },
+	{  200000, E5420_KFC_DIV(3, 3, 2), },
+	{  0 },
+};
+
 static const struct of_device_id ext_clk_match[] __initconst = {
 	{ .compatible = "samsung,exynos5420-oscclk", .data = (void *)0, },
 	{ },
@@ -1310,6 +1381,19 @@
 				ARRAY_SIZE(exynos5800_gate_clks));
 	}
 
+	if (soc == EXYNOS5420) {
+		exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk",
+			mout_cpu_p[0], mout_cpu_p[1], 0x200,
+			exynos5420_eglclk_d, ARRAY_SIZE(exynos5420_eglclk_d), 0);
+	} else {
+		exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk",
+			mout_cpu_p[0], mout_cpu_p[1], 0x200,
+			exynos5800_eglclk_d, ARRAY_SIZE(exynos5800_eglclk_d), 0);
+	}
+	exynos_register_cpu_clock(ctx, CLK_KFC_CLK, "kfcclk",
+		mout_kfc_p[0], mout_kfc_p[1], 0x28200,
+		exynos5420_kfcclk_d, ARRAY_SIZE(exynos5420_kfcclk_d), 0);
+
 	exynos5420_clk_sleep_init();
 
 	samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk-s3c2410-dclk.c b/drivers/clk/samsung/clk-s3c2410-dclk.c
index e9eb935..ec6fb14 100644
--- a/drivers/clk/samsung/clk-s3c2410-dclk.c
+++ b/drivers/clk/samsung/clk-s3c2410-dclk.c
@@ -77,12 +77,11 @@
 static int s3c24xx_clkout_set_parent(struct clk_hw *hw, u8 index)
 {
 	struct s3c24xx_clkout *clkout = to_s3c24xx_clkout(hw);
-	int ret = 0;
 
 	s3c2410_modify_misccr((clkout->mask << clkout->shift),
 			      (index << clkout->shift));
 
-	return ret;
+	return 0;
 }
 
 static const struct clk_ops s3c24xx_clkout_ops = {
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile
index 97c71c8..7e2579b 100644
--- a/drivers/clk/shmobile/Makefile
+++ b/drivers/clk/shmobile/Makefile
@@ -1,13 +1,13 @@
 obj-$(CONFIG_ARCH_EMEV2)		+= clk-emev2.o
-obj-$(CONFIG_ARCH_R7S72100)		+= clk-rz.o
-obj-$(CONFIG_ARCH_R8A73A4)		+= clk-r8a73a4.o
-obj-$(CONFIG_ARCH_R8A7740)		+= clk-r8a7740.o
-obj-$(CONFIG_ARCH_R8A7778)		+= clk-r8a7778.o
-obj-$(CONFIG_ARCH_R8A7779)		+= clk-r8a7779.o
-obj-$(CONFIG_ARCH_R8A7790)		+= clk-rcar-gen2.o
-obj-$(CONFIG_ARCH_R8A7791)		+= clk-rcar-gen2.o
-obj-$(CONFIG_ARCH_R8A7793)		+= clk-rcar-gen2.o
-obj-$(CONFIG_ARCH_R8A7794)		+= clk-rcar-gen2.o
-obj-$(CONFIG_ARCH_SH73A0)		+= clk-sh73a0.o
-obj-$(CONFIG_ARCH_SHMOBILE_MULTI)	+= clk-div6.o
-obj-$(CONFIG_ARCH_SHMOBILE_MULTI)	+= clk-mstp.o
+obj-$(CONFIG_ARCH_R7S72100)		+= clk-rz.o clk-mstp.o
+obj-$(CONFIG_ARCH_R8A73A4)		+= clk-r8a73a4.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7740)		+= clk-r8a7740.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7778)		+= clk-r8a7778.o clk-mstp.o
+obj-$(CONFIG_ARCH_R8A7779)		+= clk-r8a7779.o clk-mstp.o
+obj-$(CONFIG_ARCH_R8A7790)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7791)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7793)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7794)		+= clk-rcar-gen2.o clk-mstp.o clk-div6.o
+obj-$(CONFIG_ARCH_R8A7795)		+= renesas-cpg-mssr.o \
+					   r8a7795-cpg-mssr.o clk-div6.o
+obj-$(CONFIG_ARCH_SH73A0)		+= clk-sh73a0.o clk-mstp.o clk-div6.o
diff --git a/drivers/clk/shmobile/clk-div6.c b/drivers/clk/shmobile/clk-div6.c
index b4c8d67..9999947 100644
--- a/drivers/clk/shmobile/clk-div6.c
+++ b/drivers/clk/shmobile/clk-div6.c
@@ -18,6 +18,8 @@
 #include <linux/of_address.h>
 #include <linux/slab.h>
 
+#include "clk-div6.h"
+
 #define CPG_DIV6_CKSTP		BIT(8)
 #define CPG_DIV6_DIV(d)		((d) & 0x3f)
 #define CPG_DIV6_DIV_MASK	0x3f
@@ -172,67 +174,44 @@
 	.set_rate = cpg_div6_clock_set_rate,
 };
 
-static void __init cpg_div6_clock_init(struct device_node *np)
+
+/**
+ * cpg_div6_register - Register a DIV6 clock
+ * @name: Name of the DIV6 clock
+ * @num_parents: Number of parent clocks of the DIV6 clock (1, 4, or 8)
+ * @parent_names: Array containing the names of the parent clocks
+ * @reg: Mapped register used to control the DIV6 clock
+ */
+struct clk * __init cpg_div6_register(const char *name,
+				      unsigned int num_parents,
+				      const char **parent_names,
+				      void __iomem *reg)
 {
-	unsigned int num_parents, valid_parents;
-	const char **parent_names;
+	unsigned int valid_parents;
 	struct clk_init_data init;
 	struct div6_clock *clock;
-	const char *name;
 	struct clk *clk;
 	unsigned int i;
-	int ret;
 
 	clock = kzalloc(sizeof(*clock), GFP_KERNEL);
 	if (!clock)
-		return;
-
-	num_parents = of_clk_get_parent_count(np);
-	if (num_parents < 1) {
-		pr_err("%s: no parent found for %s DIV6 clock\n",
-		       __func__, np->name);
-		return;
-	}
+		return ERR_PTR(-ENOMEM);
 
 	clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents),
-		GFP_KERNEL);
-	parent_names = kmalloc_array(num_parents, sizeof(*parent_names),
-				GFP_KERNEL);
-	if (!parent_names)
-		return;
+				       GFP_KERNEL);
+	if (!clock->parents) {
+		clk = ERR_PTR(-ENOMEM);
+		goto free_clock;
+	}
 
-	/* Remap the clock register and read the divisor. Disabling the
-	 * clock overwrites the divisor, so we need to cache its value for the
-	 * enable operation.
+	clock->reg = reg;
+
+	/*
+	 * Read the divisor. Disabling the clock overwrites the divisor, so we
+	 * need to cache its value for the enable operation.
 	 */
-	clock->reg = of_iomap(np, 0);
-	if (clock->reg == NULL) {
-		pr_err("%s: failed to map %s DIV6 clock register\n",
-		       __func__, np->name);
-		goto error;
-	}
-
 	clock->div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1;
 
-	/* Parse the DT properties. */
-	ret = of_property_read_string(np, "clock-output-names", &name);
-	if (ret < 0) {
-		pr_err("%s: failed to get %s DIV6 clock output name\n",
-		       __func__, np->name);
-		goto error;
-	}
-
-
-	for (i = 0, valid_parents = 0; i < num_parents; i++) {
-		const char *name = of_clk_get_parent_name(np, i);
-
-		if (name) {
-			parent_names[valid_parents] = name;
-			clock->parents[valid_parents] = i;
-			valid_parents++;
-		}
-	}
-
 	switch (num_parents) {
 	case 1:
 		/* fixed parent clock */
@@ -250,8 +229,18 @@
 		break;
 	default:
 		pr_err("%s: invalid number of parents for DIV6 clock %s\n",
-		       __func__, np->name);
-		goto error;
+		       __func__, name);
+		clk = ERR_PTR(-EINVAL);
+		goto free_parents;
+	}
+
+	/* Filter out invalid parents */
+	for (i = 0, valid_parents = 0; i < num_parents; i++) {
+		if (parent_names[i]) {
+			parent_names[valid_parents] = parent_names[i];
+			clock->parents[valid_parents] = i;
+			valid_parents++;
+		}
 	}
 
 	/* Register the clock. */
@@ -264,6 +253,53 @@
 	clock->hw.init = &init;
 
 	clk = clk_register(NULL, &clock->hw);
+	if (IS_ERR(clk))
+		goto free_parents;
+
+	return clk;
+
+free_parents:
+	kfree(clock->parents);
+free_clock:
+	kfree(clock);
+	return clk;
+}
+
+static void __init cpg_div6_clock_init(struct device_node *np)
+{
+	unsigned int num_parents;
+	const char **parent_names;
+	const char *clk_name = np->name;
+	void __iomem *reg;
+	struct clk *clk;
+	unsigned int i;
+
+	num_parents = of_clk_get_parent_count(np);
+	if (num_parents < 1) {
+		pr_err("%s: no parent found for %s DIV6 clock\n",
+		       __func__, np->name);
+		return;
+	}
+
+	parent_names = kmalloc_array(num_parents, sizeof(*parent_names),
+				GFP_KERNEL);
+	if (!parent_names)
+		return;
+
+	reg = of_iomap(np, 0);
+	if (reg == NULL) {
+		pr_err("%s: failed to map %s DIV6 clock register\n",
+		       __func__, np->name);
+		goto error;
+	}
+
+	/* Parse the DT properties. */
+	of_property_read_string(np, "clock-output-names", &clk_name);
+
+	for (i = 0; i < num_parents; i++)
+		parent_names[i] = of_clk_get_parent_name(np, i);
+
+	clk = cpg_div6_register(clk_name, num_parents, parent_names, reg);
 	if (IS_ERR(clk)) {
 		pr_err("%s: failed to register %s DIV6 clock (%ld)\n",
 		       __func__, np->name, PTR_ERR(clk));
@@ -276,9 +312,8 @@
 	return;
 
 error:
-	if (clock->reg)
-		iounmap(clock->reg);
+	if (reg)
+		iounmap(reg);
 	kfree(parent_names);
-	kfree(clock);
 }
 CLK_OF_DECLARE(cpg_div6_clk, "renesas,cpg-div6-clock", cpg_div6_clock_init);
diff --git a/drivers/clk/shmobile/clk-div6.h b/drivers/clk/shmobile/clk-div6.h
new file mode 100644
index 0000000..9a85a95
--- /dev/null
+++ b/drivers/clk/shmobile/clk-div6.h
@@ -0,0 +1,7 @@
+#ifndef __SHMOBILE_CLK_DIV6_H__
+#define __SHMOBILE_CLK_DIV6_H__
+
+struct clk *cpg_div6_register(const char *name, unsigned int num_parents,
+			      const char **parent_names, void __iomem *reg);
+
+#endif
diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c
index 745496f..8419772 100644
--- a/drivers/clk/shmobile/clk-rcar-gen2.c
+++ b/drivers/clk/shmobile/clk-rcar-gen2.c
@@ -115,7 +115,7 @@
 	 *
 	 * Using experimental measurements, it seems that no more than
 	 * ~10 iterations are needed, independently of the CPU rate.
-	 * Since this value might be dependant of external xtal rate, pll1
+	 * Since this value might be dependent on external xtal rate, pll1
 	 * rate or even the other emulation clocks rate, use 1000 as a
 	 * "super" safe value.
 	 */
@@ -262,7 +262,7 @@
  * 1  1  0	30 / 2		x172/2	x208/2	x106
  * 1  1  1	30 / 2		x172/2	x208/2	x88
  *
- * *1 :	Table 7.6 indicates VCO ouput (PLLx = VCO/2)
+ * *1 :	Table 7.6 indicates VCO output (PLLx = VCO/2)
  */
 #define CPG_PLL_CONFIG_INDEX(md)	((((md) & BIT(14)) >> 12) | \
 					 (((md) & BIT(13)) >> 12) | \
diff --git a/drivers/clk/shmobile/r8a7795-cpg-mssr.c b/drivers/clk/shmobile/r8a7795-cpg-mssr.c
new file mode 100644
index 0000000..13e9947
--- /dev/null
+++ b/drivers/clk/shmobile/r8a7795-cpg-mssr.c
@@ -0,0 +1,383 @@
+/*
+ * r8a7795 Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2015 Glider bvba
+ *
+ * Based on clk-rcar-gen3.c
+ *
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/bug.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+#include <dt-bindings/clock/r8a7795-cpg-mssr.h>
+
+#include "renesas-cpg-mssr.h"
+
+
+enum clk_ids {
+	/* Core Clock Outputs exported to DT */
+	LAST_DT_CORE_CLK = R8A7795_CLK_OSC,
+
+	/* External Input Clocks */
+	CLK_EXTAL,
+	CLK_EXTALR,
+
+	/* Internal Core Clocks */
+	CLK_MAIN,
+	CLK_PLL0,
+	CLK_PLL1,
+	CLK_PLL2,
+	CLK_PLL3,
+	CLK_PLL4,
+	CLK_PLL1_DIV2,
+	CLK_PLL1_DIV4,
+	CLK_S0,
+	CLK_S1,
+	CLK_S2,
+	CLK_S3,
+	CLK_SDSRC,
+	CLK_SSPSRC,
+
+	/* Module Clocks */
+	MOD_CLK_BASE
+};
+
+enum r8a7795_clk_types {
+	CLK_TYPE_GEN3_MAIN = CLK_TYPE_CUSTOM,
+	CLK_TYPE_GEN3_PLL0,
+	CLK_TYPE_GEN3_PLL1,
+	CLK_TYPE_GEN3_PLL2,
+	CLK_TYPE_GEN3_PLL3,
+	CLK_TYPE_GEN3_PLL4,
+};
+
+static const struct cpg_core_clk r8a7795_core_clks[] __initconst = {
+	/* External Clock Inputs */
+	DEF_INPUT("extal",  CLK_EXTAL),
+	DEF_INPUT("extalr", CLK_EXTALR),
+
+	/* Internal Core Clocks */
+	DEF_BASE(".main",       CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL),
+	DEF_BASE(".pll0",       CLK_PLL0, CLK_TYPE_GEN3_PLL0, CLK_MAIN),
+	DEF_BASE(".pll1",       CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN),
+	DEF_BASE(".pll2",       CLK_PLL2, CLK_TYPE_GEN3_PLL2, CLK_MAIN),
+	DEF_BASE(".pll3",       CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN),
+	DEF_BASE(".pll4",       CLK_PLL4, CLK_TYPE_GEN3_PLL4, CLK_MAIN),
+
+	DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2,     CLK_PLL1,       2, 1),
+	DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4,     CLK_PLL1_DIV2,  2, 1),
+	DEF_FIXED(".s0",        CLK_S0,            CLK_PLL1_DIV2,  2, 1),
+	DEF_FIXED(".s1",        CLK_S1,            CLK_PLL1_DIV2,  3, 1),
+	DEF_FIXED(".s2",        CLK_S2,            CLK_PLL1_DIV2,  4, 1),
+	DEF_FIXED(".s3",        CLK_S3,            CLK_PLL1_DIV2,  6, 1),
+
+	/* Core Clock Outputs */
+	DEF_FIXED("ztr",        R8A7795_CLK_ZTR,   CLK_PLL1_DIV2,  6, 1),
+	DEF_FIXED("ztrd2",      R8A7795_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1),
+	DEF_FIXED("zt",         R8A7795_CLK_ZT,    CLK_PLL1_DIV2,  4, 1),
+	DEF_FIXED("zx",         R8A7795_CLK_ZX,    CLK_PLL1_DIV2,  2, 1),
+	DEF_FIXED("s0d1",       R8A7795_CLK_S0D1,  CLK_S0,         1, 1),
+	DEF_FIXED("s0d4",       R8A7795_CLK_S0D4,  CLK_S0,         4, 1),
+	DEF_FIXED("s1d1",       R8A7795_CLK_S1D1,  CLK_S1,         1, 1),
+	DEF_FIXED("s1d2",       R8A7795_CLK_S1D2,  CLK_S1,         2, 1),
+	DEF_FIXED("s1d4",       R8A7795_CLK_S1D4,  CLK_S1,         4, 1),
+	DEF_FIXED("s2d1",       R8A7795_CLK_S2D1,  CLK_S2,         1, 1),
+	DEF_FIXED("s2d2",       R8A7795_CLK_S2D2,  CLK_S2,         2, 1),
+	DEF_FIXED("s2d4",       R8A7795_CLK_S2D4,  CLK_S2,         4, 1),
+	DEF_FIXED("s3d1",       R8A7795_CLK_S3D1,  CLK_S3,         1, 1),
+	DEF_FIXED("s3d2",       R8A7795_CLK_S3D2,  CLK_S3,         2, 1),
+	DEF_FIXED("s3d4",       R8A7795_CLK_S3D4,  CLK_S3,         4, 1),
+	DEF_FIXED("cl",         R8A7795_CLK_CL,    CLK_PLL1_DIV2, 48, 1),
+	DEF_FIXED("cp",         R8A7795_CLK_CP,    CLK_EXTAL,      2, 1),
+
+	DEF_DIV6P1("mso",       R8A7795_CLK_MSO,   CLK_PLL1_DIV4, 0x014),
+	DEF_DIV6P1("hdmi",      R8A7795_CLK_HDMI,  CLK_PLL1_DIV2, 0x250),
+};
+
+static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = {
+	DEF_MOD("scif5",		 202,	R8A7795_CLK_S3D4),
+	DEF_MOD("scif4",		 203,	R8A7795_CLK_S3D4),
+	DEF_MOD("scif3",		 204,	R8A7795_CLK_S3D4),
+	DEF_MOD("scif1",		 206,	R8A7795_CLK_S3D4),
+	DEF_MOD("scif0",		 207,	R8A7795_CLK_S3D4),
+	DEF_MOD("msiof3",		 208,	R8A7795_CLK_MSO),
+	DEF_MOD("msiof2",		 209,	R8A7795_CLK_MSO),
+	DEF_MOD("msiof1",		 210,	R8A7795_CLK_MSO),
+	DEF_MOD("msiof0",		 211,	R8A7795_CLK_MSO),
+	DEF_MOD("sys-dmac2",		 217,	R8A7795_CLK_S3D1),
+	DEF_MOD("sys-dmac1",		 218,	R8A7795_CLK_S3D1),
+	DEF_MOD("sys-dmac0",		 219,	R8A7795_CLK_S3D1),
+	DEF_MOD("scif2",		 310,	R8A7795_CLK_S3D4),
+	DEF_MOD("pcie1",		 318,	R8A7795_CLK_S3D1),
+	DEF_MOD("pcie0",		 319,	R8A7795_CLK_S3D1),
+	DEF_MOD("intc-ap",		 408,	R8A7795_CLK_S3D1),
+	DEF_MOD("audmac0",		 502,	R8A7795_CLK_S3D4),
+	DEF_MOD("audmac1",		 501,	R8A7795_CLK_S3D4),
+	DEF_MOD("hscif4",		 516,	R8A7795_CLK_S3D1),
+	DEF_MOD("hscif3",		 517,	R8A7795_CLK_S3D1),
+	DEF_MOD("hscif2",		 518,	R8A7795_CLK_S3D1),
+	DEF_MOD("hscif1",		 519,	R8A7795_CLK_S3D1),
+	DEF_MOD("hscif0",		 520,	R8A7795_CLK_S3D1),
+	DEF_MOD("vspd3",		 620,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspd2",		 621,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspd1",		 622,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspd0",		 623,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspbc",		 624,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspbd",		 626,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspi2",		 629,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspi1",		 630,	R8A7795_CLK_S2D1),
+	DEF_MOD("vspi0",		 631,	R8A7795_CLK_S2D1),
+	DEF_MOD("ehci2",		 701,	R8A7795_CLK_S3D4),
+	DEF_MOD("ehci1",		 702,	R8A7795_CLK_S3D4),
+	DEF_MOD("ehci0",		 703,	R8A7795_CLK_S3D4),
+	DEF_MOD("hsusb",		 704,	R8A7795_CLK_S3D4),
+	DEF_MOD("du3",			 721,	R8A7795_CLK_S2D1),
+	DEF_MOD("du2",			 722,	R8A7795_CLK_S2D1),
+	DEF_MOD("du1",			 723,	R8A7795_CLK_S2D1),
+	DEF_MOD("du0",			 724,	R8A7795_CLK_S2D1),
+	DEF_MOD("hdmi1",		 728,	R8A7795_CLK_HDMI),
+	DEF_MOD("hdmi0",		 729,	R8A7795_CLK_HDMI),
+	DEF_MOD("etheravb",		 812,	R8A7795_CLK_S3D2),
+	DEF_MOD("sata0",		 815,	R8A7795_CLK_S3D2),
+	DEF_MOD("gpio7",		 905,	R8A7795_CLK_CP),
+	DEF_MOD("gpio6",		 906,	R8A7795_CLK_CP),
+	DEF_MOD("gpio5",		 907,	R8A7795_CLK_CP),
+	DEF_MOD("gpio4",		 908,	R8A7795_CLK_CP),
+	DEF_MOD("gpio3",		 909,	R8A7795_CLK_CP),
+	DEF_MOD("gpio2",		 910,	R8A7795_CLK_CP),
+	DEF_MOD("gpio1",		 911,	R8A7795_CLK_CP),
+	DEF_MOD("gpio0",		 912,	R8A7795_CLK_CP),
+	DEF_MOD("i2c6",			 918,	R8A7795_CLK_S3D2),
+	DEF_MOD("i2c5",			 919,	R8A7795_CLK_S3D2),
+	DEF_MOD("i2c4",			 927,	R8A7795_CLK_S3D2),
+	DEF_MOD("i2c3",			 928,	R8A7795_CLK_S3D2),
+	DEF_MOD("i2c2",			 929,	R8A7795_CLK_S3D2),
+	DEF_MOD("i2c1",			 930,	R8A7795_CLK_S3D2),
+	DEF_MOD("i2c0",			 931,	R8A7795_CLK_S3D2),
+	DEF_MOD("ssi-all",		1005,	R8A7795_CLK_S3D4),
+	DEF_MOD("ssi9",			1006,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi8",			1007,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi7",			1008,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi6",			1009,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi5",			1010,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi4",			1011,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi3",			1012,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi2",			1013,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi1",			1014,	MOD_CLK_ID(1005)),
+	DEF_MOD("ssi0",			1015,	MOD_CLK_ID(1005)),
+	DEF_MOD("scu-all",		1017,	R8A7795_CLK_S3D4),
+	DEF_MOD("scu-dvc1",		1018,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-dvc0",		1019,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-ctu1-mix1",	1020,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-ctu0-mix0",	1021,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src9",		1022,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src8",		1023,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src7",		1024,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src6",		1025,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src5",		1026,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src4",		1027,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src3",		1028,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src2",		1029,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src1",		1030,	MOD_CLK_ID(1017)),
+	DEF_MOD("scu-src0",		1031,	MOD_CLK_ID(1017)),
+};
+
+static const unsigned int r8a7795_crit_mod_clks[] __initconst = {
+	MOD_CLK_ID(408),	/* INTC-AP (GIC) */
+};
+
+
+#define CPG_PLL0CR	0x00d8
+#define CPG_PLL2CR	0x002c
+#define CPG_PLL4CR	0x01f4
+
+/*
+ * CPG Clock Data
+ */
+
+/*
+ *   MD		EXTAL		PLL0	PLL1	PLL2	PLL3	PLL4
+ * 14 13 19 17	(MHz)
+ *-------------------------------------------------------------------
+ * 0  0  0  0	16.66 x 1	x180	x192	x144	x192	x144
+ * 0  0  0  1	16.66 x 1	x180	x192	x144	x128	x144
+ * 0  0  1  0	Prohibited setting
+ * 0  0  1  1	16.66 x 1	x180	x192	x144	x192	x144
+ * 0  1  0  0	20    x 1	x150	x160	x120	x160	x120
+ * 0  1  0  1	20    x 1	x150	x160	x120	x106	x120
+ * 0  1  1  0	Prohibited setting
+ * 0  1  1  1	20    x 1	x150	x160	x120	x160	x120
+ * 1  0  0  0	25    x 1	x120	x128	x96	x128	x96
+ * 1  0  0  1	25    x 1	x120	x128	x96	x84	x96
+ * 1  0  1  0	Prohibited setting
+ * 1  0  1  1	25    x 1	x120	x128	x96	x128	x96
+ * 1  1  0  0	33.33 / 2	x180	x192	x144	x192	x144
+ * 1  1  0  1	33.33 / 2	x180	x192	x144	x128	x144
+ * 1  1  1  0	Prohibited setting
+ * 1  1  1  1	33.33 / 2	x180	x192	x144	x192	x144
+ */
+#define CPG_PLL_CONFIG_INDEX(md)	((((md) & BIT(14)) >> 11) | \
+					 (((md) & BIT(13)) >> 11) | \
+					 (((md) & BIT(19)) >> 18) | \
+					 (((md) & BIT(17)) >> 17))
+
+struct cpg_pll_config {
+	unsigned int extal_div;
+	unsigned int pll1_mult;
+	unsigned int pll3_mult;
+};
+
+static const struct cpg_pll_config cpg_pll_configs[16] __initconst = {
+	/* EXTAL div	PLL1 mult	PLL3 mult */
+	{ 1,		192,		192,	},
+	{ 1,		192,		128,	},
+	{ 0, /* Prohibited setting */		},
+	{ 1,		192,		192,	},
+	{ 1,		160,		160,	},
+	{ 1,		160,		106,	},
+	{ 0, /* Prohibited setting */		},
+	{ 1,		160,		160,	},
+	{ 1,		128,		128,	},
+	{ 1,		128,		84,	},
+	{ 0, /* Prohibited setting */		},
+	{ 1,		128,		128,	},
+	{ 2,		192,		192,	},
+	{ 2,		192,		128,	},
+	{ 0, /* Prohibited setting */		},
+	{ 2,		192,		192,	},
+};
+
+static const struct cpg_pll_config *cpg_pll_config __initdata;
+
+static
+struct clk * __init r8a7795_cpg_clk_register(struct device *dev,
+					     const struct cpg_core_clk *core,
+					     const struct cpg_mssr_info *info,
+					     struct clk **clks,
+					     void __iomem *base)
+{
+	const struct clk *parent;
+	unsigned int mult = 1;
+	unsigned int div = 1;
+	u32 value;
+
+	parent = clks[core->parent];
+	if (IS_ERR(parent))
+		return ERR_CAST(parent);
+
+	switch (core->type) {
+	case CLK_TYPE_GEN3_MAIN:
+		div = cpg_pll_config->extal_div;
+		break;
+
+	case CLK_TYPE_GEN3_PLL0:
+		/*
+		 * PLL0 is a configurable multiplier clock. Register it as a
+		 * fixed factor clock for now as there's no generic multiplier
+		 * clock implementation and we currently have no need to change
+		 * the multiplier value.
+		 */
+		value = readl(base + CPG_PLL0CR);
+		mult = (((value >> 24) & 0x7f) + 1) * 2;
+		break;
+
+	case CLK_TYPE_GEN3_PLL1:
+		mult = cpg_pll_config->pll1_mult;
+		break;
+
+	case CLK_TYPE_GEN3_PLL2:
+		/*
+		 * PLL2 is a configurable multiplier clock. Register it as a
+		 * fixed factor clock for now as there's no generic multiplier
+		 * clock implementation and we currently have no need to change
+		 * the multiplier value.
+		 */
+		value = readl(base + CPG_PLL2CR);
+		mult = (((value >> 24) & 0x7f) + 1) * 2;
+		break;
+
+	case CLK_TYPE_GEN3_PLL3:
+		mult = cpg_pll_config->pll3_mult;
+		break;
+
+	case CLK_TYPE_GEN3_PLL4:
+		/*
+		 * PLL4 is a configurable multiplier clock. Register it as a
+		 * fixed factor clock for now as there's no generic multiplier
+		 * clock implementation and we currently have no need to change
+		 * the multiplier value.
+		 */
+		value = readl(base + CPG_PLL4CR);
+		mult = (((value >> 24) & 0x7f) + 1) * 2;
+		break;
+
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+
+	return clk_register_fixed_factor(NULL, core->name,
+					 __clk_get_name(parent), 0, mult, div);
+}
+
+/*
+ * Reset register definitions.
+ */
+#define MODEMR	0xe6160060
+
+static u32 rcar_gen3_read_mode_pins(void)
+{
+	void __iomem *modemr = ioremap_nocache(MODEMR, 4);
+	u32 mode;
+
+	BUG_ON(!modemr);
+	mode = ioread32(modemr);
+	iounmap(modemr);
+
+	return mode;
+}
+
+static int __init r8a7795_cpg_mssr_init(struct device *dev)
+{
+	u32 cpg_mode = rcar_gen3_read_mode_pins();
+
+	cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
+	if (!cpg_pll_config->extal_div) {
+		dev_err(dev, "Prohibited setting (cpg_mode=0x%x)\n", cpg_mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+const struct cpg_mssr_info r8a7795_cpg_mssr_info __initconst = {
+	/* Core Clocks */
+	.core_clks = r8a7795_core_clks,
+	.num_core_clks = ARRAY_SIZE(r8a7795_core_clks),
+	.last_dt_core_clk = LAST_DT_CORE_CLK,
+	.num_total_core_clks = MOD_CLK_BASE,
+
+	/* Module Clocks */
+	.mod_clks = r8a7795_mod_clks,
+	.num_mod_clks = ARRAY_SIZE(r8a7795_mod_clks),
+	.num_hw_mod_clks = 12 * 32,
+
+	/* Critical Module Clocks */
+	.crit_mod_clks = r8a7795_crit_mod_clks,
+	.num_crit_mod_clks = ARRAY_SIZE(r8a7795_crit_mod_clks),
+
+	/* Callbacks */
+	.init = r8a7795_cpg_mssr_init,
+	.cpg_clk_register = r8a7795_cpg_clk_register,
+};
diff --git a/drivers/clk/shmobile/renesas-cpg-mssr.c b/drivers/clk/shmobile/renesas-cpg-mssr.c
new file mode 100644
index 0000000..9a4d888
--- /dev/null
+++ b/drivers/clk/shmobile/renesas-cpg-mssr.c
@@ -0,0 +1,596 @@
+/*
+ * Renesas Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2015 Glider bvba
+ *
+ * Based on clk-mstp.c, clk-rcar-gen2.c, and clk-rcar-gen3.c
+ *
+ * Copyright (C) 2013 Ideas On Board SPRL
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
+#include <linux/pm_domain.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+#include "renesas-cpg-mssr.h"
+#include "clk-div6.h"
+
+#ifdef DEBUG
+#define WARN_DEBUG(x)	do { } while (0)
+#else
+#define WARN_DEBUG(x)	WARN_ON(x)
+#endif
+
+
+/*
+ * Module Standby and Software Reset register offets.
+ *
+ * If the registers exist, these are valid for SH-Mobile, R-Mobile,
+ * R-Car Gen 2, and R-Car Gen 3.
+ * These are NOT valid for R-Car Gen1 and RZ/A1!
+ */
+
+/*
+ * Module Stop Status Register offsets
+ */
+
+static const u16 mstpsr[] = {
+	0x030, 0x038, 0x040, 0x048, 0x04C, 0x03C, 0x1C0, 0x1C4,
+	0x9A0, 0x9A4, 0x9A8, 0x9AC,
+};
+
+#define	MSTPSR(i)	mstpsr[i]
+
+
+/*
+ * System Module Stop Control Register offsets
+ */
+
+static const u16 smstpcr[] = {
+	0x130, 0x134, 0x138, 0x13C, 0x140, 0x144, 0x148, 0x14C,
+	0x990, 0x994, 0x998, 0x99C,
+};
+
+#define	SMSTPCR(i)	smstpcr[i]
+
+
+/*
+ * Software Reset Register offsets
+ */
+
+static const u16 srcr[] = {
+	0x0A0, 0x0A8, 0x0B0, 0x0B8, 0x0BC, 0x0C4, 0x1C8, 0x1CC,
+	0x920, 0x924, 0x928, 0x92C,
+};
+
+#define	SRCR(i)		srcr[i]
+
+
+/* Realtime Module Stop Control Register offsets */
+#define RMSTPCR(i)	(smstpcr[i] - 0x20)
+
+/* Modem Module Stop Control Register offsets (r8a73a4) */
+#define MMSTPCR(i)	(smstpcr[i] + 0x20)
+
+/* Software Reset Clearing Register offsets */
+#define	SRSTCLR(i)	(0x940 + (i) * 4)
+
+
+/**
+ * Clock Pulse Generator / Module Standby and Software Reset Private Data
+ *
+ * @dev: CPG/MSSR device
+ * @base: CPG/MSSR register block base address
+ * @mstp_lock: protects writes to SMSTPCR
+ * @clks: Array containing all Core and Module Clocks
+ * @num_core_clks: Number of Core Clocks in clks[]
+ * @num_mod_clks: Number of Module Clocks in clks[]
+ * @last_dt_core_clk: ID of the last Core Clock exported to DT
+ */
+struct cpg_mssr_priv {
+	struct device *dev;
+	void __iomem *base;
+	spinlock_t mstp_lock;
+
+	struct clk **clks;
+	unsigned int num_core_clks;
+	unsigned int num_mod_clks;
+	unsigned int last_dt_core_clk;
+};
+
+
+/**
+ * struct mstp_clock - MSTP gating clock
+ * @hw: handle between common and hardware-specific interfaces
+ * @index: MSTP clock number
+ * @priv: CPG/MSSR private data
+ */
+struct mstp_clock {
+	struct clk_hw hw;
+	u32 index;
+	struct cpg_mssr_priv *priv;
+};
+
+#define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw)
+
+static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
+{
+	struct mstp_clock *clock = to_mstp_clock(hw);
+	struct cpg_mssr_priv *priv = clock->priv;
+	unsigned int reg = clock->index / 32;
+	unsigned int bit = clock->index % 32;
+	struct device *dev = priv->dev;
+	u32 bitmask = BIT(bit);
+	unsigned long flags;
+	unsigned int i;
+	u32 value;
+
+	dev_dbg(dev, "MSTP %u%02u/%pC %s\n", reg, bit, hw->clk,
+		enable ? "ON" : "OFF");
+	spin_lock_irqsave(&priv->mstp_lock, flags);
+
+	value = clk_readl(priv->base + SMSTPCR(reg));
+	if (enable)
+		value &= ~bitmask;
+	else
+		value |= bitmask;
+	clk_writel(value, priv->base + SMSTPCR(reg));
+
+	spin_unlock_irqrestore(&priv->mstp_lock, flags);
+
+	if (!enable)
+		return 0;
+
+	for (i = 1000; i > 0; --i) {
+		if (!(clk_readl(priv->base + MSTPSR(reg)) &
+		      bitmask))
+			break;
+		cpu_relax();
+	}
+
+	if (!i) {
+		dev_err(dev, "Failed to enable SMSTP %p[%d]\n",
+			priv->base + SMSTPCR(reg), bit);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int cpg_mstp_clock_enable(struct clk_hw *hw)
+{
+	return cpg_mstp_clock_endisable(hw, true);
+}
+
+static void cpg_mstp_clock_disable(struct clk_hw *hw)
+{
+	cpg_mstp_clock_endisable(hw, false);
+}
+
+static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
+{
+	struct mstp_clock *clock = to_mstp_clock(hw);
+	struct cpg_mssr_priv *priv = clock->priv;
+	u32 value;
+
+	value = clk_readl(priv->base + MSTPSR(clock->index / 32));
+
+	return !(value & BIT(clock->index % 32));
+}
+
+static const struct clk_ops cpg_mstp_clock_ops = {
+	.enable = cpg_mstp_clock_enable,
+	.disable = cpg_mstp_clock_disable,
+	.is_enabled = cpg_mstp_clock_is_enabled,
+};
+
+static
+struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec,
+					 void *data)
+{
+	unsigned int clkidx = clkspec->args[1];
+	struct cpg_mssr_priv *priv = data;
+	struct device *dev = priv->dev;
+	unsigned int idx;
+	const char *type;
+	struct clk *clk;
+
+	switch (clkspec->args[0]) {
+	case CPG_CORE:
+		type = "core";
+		if (clkidx > priv->last_dt_core_clk) {
+			dev_err(dev, "Invalid %s clock index %u\n", type,
+			       clkidx);
+			return ERR_PTR(-EINVAL);
+		}
+		clk = priv->clks[clkidx];
+		break;
+
+	case CPG_MOD:
+		type = "module";
+		idx = MOD_CLK_PACK(clkidx);
+		if (clkidx % 100 > 31 || idx >= priv->num_mod_clks) {
+			dev_err(dev, "Invalid %s clock index %u\n", type,
+				clkidx);
+			return ERR_PTR(-EINVAL);
+		}
+		clk = priv->clks[priv->num_core_clks + idx];
+		break;
+
+	default:
+		dev_err(dev, "Invalid CPG clock type %u\n", clkspec->args[0]);
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (IS_ERR(clk))
+		dev_err(dev, "Cannot get %s clock %u: %ld", type, clkidx,
+		       PTR_ERR(clk));
+	else
+		dev_dbg(dev, "clock (%u, %u) is %pC at %pCr Hz\n",
+			clkspec->args[0], clkspec->args[1], clk, clk);
+	return clk;
+}
+
+static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
+					      const struct cpg_mssr_info *info,
+					      struct cpg_mssr_priv *priv)
+{
+	struct clk *clk = NULL, *parent;
+	struct device *dev = priv->dev;
+	unsigned int id = core->id;
+	const char *parent_name;
+
+	WARN_DEBUG(id >= priv->num_core_clks);
+	WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
+
+	switch (core->type) {
+	case CLK_TYPE_IN:
+		clk = of_clk_get_by_name(priv->dev->of_node, core->name);
+		break;
+
+	case CLK_TYPE_FF:
+	case CLK_TYPE_DIV6P1:
+		WARN_DEBUG(core->parent >= priv->num_core_clks);
+		parent = priv->clks[core->parent];
+		if (IS_ERR(parent)) {
+			clk = parent;
+			goto fail;
+		}
+
+		parent_name = __clk_get_name(parent);
+		if (core->type == CLK_TYPE_FF) {
+			clk = clk_register_fixed_factor(NULL, core->name,
+							parent_name, 0,
+							core->mult, core->div);
+		} else {
+			clk = cpg_div6_register(core->name, 1, &parent_name,
+						priv->base + core->offset);
+		}
+		break;
+
+	default:
+		if (info->cpg_clk_register)
+			clk = info->cpg_clk_register(dev, core, info,
+						     priv->clks, priv->base);
+		else
+			dev_err(dev, "%s has unsupported core clock type %u\n",
+				core->name, core->type);
+		break;
+	}
+
+	if (IS_ERR_OR_NULL(clk))
+		goto fail;
+
+	dev_dbg(dev, "Core clock %pC at %pCr Hz\n", clk, clk);
+	priv->clks[id] = clk;
+	return;
+
+fail:
+	dev_err(dev, "Failed to register %s clock %s: %ld\n", "core,",
+		core->name, PTR_ERR(clk));
+}
+
+static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod,
+					     const struct cpg_mssr_info *info,
+					     struct cpg_mssr_priv *priv)
+{
+	struct mstp_clock *clock = NULL;
+	struct device *dev = priv->dev;
+	unsigned int id = mod->id;
+	struct clk_init_data init;
+	struct clk *parent, *clk;
+	const char *parent_name;
+	unsigned int i;
+
+	WARN_DEBUG(id < priv->num_core_clks);
+	WARN_DEBUG(id >= priv->num_core_clks + priv->num_mod_clks);
+	WARN_DEBUG(mod->parent >= priv->num_core_clks + priv->num_mod_clks);
+	WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
+
+	parent = priv->clks[mod->parent];
+	if (IS_ERR(parent)) {
+		clk = parent;
+		goto fail;
+	}
+
+	clock = kzalloc(sizeof(*clock), GFP_KERNEL);
+	if (!clock) {
+		clk = ERR_PTR(-ENOMEM);
+		goto fail;
+	}
+
+	init.name = mod->name;
+	init.ops = &cpg_mstp_clock_ops;
+	init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
+	for (i = 0; i < info->num_crit_mod_clks; i++)
+		if (id == info->crit_mod_clks[i]) {
+#ifdef CLK_ENABLE_HAND_OFF
+			dev_dbg(dev, "MSTP %s setting CLK_ENABLE_HAND_OFF\n",
+				mod->name);
+			init.flags |= CLK_ENABLE_HAND_OFF;
+			break;
+#else
+			dev_dbg(dev, "Ignoring MSTP %s to prevent disabling\n",
+				mod->name);
+			return;
+#endif
+		}
+
+	parent_name = __clk_get_name(parent);
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	clock->index = id - priv->num_core_clks;
+	clock->priv = priv;
+	clock->hw.init = &init;
+
+	clk = clk_register(NULL, &clock->hw);
+	if (IS_ERR(clk))
+		goto fail;
+
+	dev_dbg(dev, "Module clock %pC at %pCr Hz\n", clk, clk);
+	priv->clks[id] = clk;
+	return;
+
+fail:
+	dev_err(dev, "Failed to register %s clock %s: %ld\n", "module,",
+		mod->name, PTR_ERR(clk));
+	kfree(clock);
+}
+
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
+struct cpg_mssr_clk_domain {
+	struct generic_pm_domain genpd;
+	struct device_node *np;
+	unsigned int num_core_pm_clks;
+	unsigned int core_pm_clks[0];
+};
+
+static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec,
+			       struct cpg_mssr_clk_domain *pd)
+{
+	unsigned int i;
+
+	if (clkspec->np != pd->np || clkspec->args_count != 2)
+		return false;
+
+	switch (clkspec->args[0]) {
+	case CPG_CORE:
+		for (i = 0; i < pd->num_core_pm_clks; i++)
+			if (clkspec->args[1] == pd->core_pm_clks[i])
+				return true;
+		return false;
+
+	case CPG_MOD:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+static int cpg_mssr_attach_dev(struct generic_pm_domain *genpd,
+			       struct device *dev)
+{
+	struct cpg_mssr_clk_domain *pd =
+		container_of(genpd, struct cpg_mssr_clk_domain, genpd);
+	struct device_node *np = dev->of_node;
+	struct of_phandle_args clkspec;
+	struct clk *clk;
+	int i = 0;
+	int error;
+
+	while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i,
+					   &clkspec)) {
+		if (cpg_mssr_is_pm_clk(&clkspec, pd))
+			goto found;
+
+		of_node_put(clkspec.np);
+		i++;
+	}
+
+	return 0;
+
+found:
+	clk = of_clk_get_from_provider(&clkspec);
+	of_node_put(clkspec.np);
+
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	error = pm_clk_create(dev);
+	if (error) {
+		dev_err(dev, "pm_clk_create failed %d\n", error);
+		goto fail_put;
+	}
+
+	error = pm_clk_add_clk(dev, clk);
+	if (error) {
+		dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error);
+		goto fail_destroy;
+	}
+
+	return 0;
+
+fail_destroy:
+	pm_clk_destroy(dev);
+fail_put:
+	clk_put(clk);
+	return error;
+}
+
+static void cpg_mssr_detach_dev(struct generic_pm_domain *genpd,
+				struct device *dev)
+{
+	if (!list_empty(&dev->power.subsys_data->clock_list))
+		pm_clk_destroy(dev);
+}
+
+static int __init cpg_mssr_add_clk_domain(struct device *dev,
+					  const unsigned int *core_pm_clks,
+					  unsigned int num_core_pm_clks)
+{
+	struct device_node *np = dev->of_node;
+	struct generic_pm_domain *genpd;
+	struct cpg_mssr_clk_domain *pd;
+	size_t pm_size = num_core_pm_clks * sizeof(core_pm_clks[0]);
+
+	pd = devm_kzalloc(dev, sizeof(*pd) + pm_size, GFP_KERNEL);
+	if (!pd)
+		return -ENOMEM;
+
+	pd->np = np;
+	pd->num_core_pm_clks = num_core_pm_clks;
+	memcpy(pd->core_pm_clks, core_pm_clks, pm_size);
+
+	genpd = &pd->genpd;
+	genpd->name = np->name;
+	genpd->flags = GENPD_FLAG_PM_CLK;
+	pm_genpd_init(genpd, &simple_qos_governor, false);
+	genpd->attach_dev = cpg_mssr_attach_dev;
+	genpd->detach_dev = cpg_mssr_detach_dev;
+
+	of_genpd_add_provider_simple(np, genpd);
+	return 0;
+}
+#else
+static inline int cpg_mssr_add_clk_domain(struct device *dev,
+					  const unsigned int *core_pm_clks,
+					  unsigned int num_core_pm_clks)
+{
+	return 0;
+}
+#endif /* !CONFIG_PM_GENERIC_DOMAINS_OF */
+
+
+static const struct of_device_id cpg_mssr_match[] = {
+#ifdef CONFIG_ARCH_R8A7795
+	{
+		.compatible = "renesas,r8a7795-cpg-mssr",
+		.data = &r8a7795_cpg_mssr_info,
+	},
+#endif
+	{ /* sentinel */ }
+};
+
+static void cpg_mssr_del_clk_provider(void *data)
+{
+	of_clk_del_provider(data);
+}
+
+static int __init cpg_mssr_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	const struct cpg_mssr_info *info;
+	struct cpg_mssr_priv *priv;
+	unsigned int nclks, i;
+	struct resource *res;
+	struct clk **clks;
+	int error;
+
+	info = of_match_node(cpg_mssr_match, np)->data;
+	if (info->init) {
+		error = info->init(dev);
+		if (error)
+			return error;
+	}
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+	spin_lock_init(&priv->mstp_lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	nclks = info->num_total_core_clks + info->num_hw_mod_clks;
+	clks = devm_kmalloc_array(dev, nclks, sizeof(*clks), GFP_KERNEL);
+	if (!clks)
+		return -ENOMEM;
+
+	priv->clks = clks;
+	priv->num_core_clks = info->num_total_core_clks;
+	priv->num_mod_clks = info->num_hw_mod_clks;
+	priv->last_dt_core_clk = info->last_dt_core_clk;
+
+	for (i = 0; i < nclks; i++)
+		clks[i] = ERR_PTR(-ENOENT);
+
+	for (i = 0; i < info->num_core_clks; i++)
+		cpg_mssr_register_core_clk(&info->core_clks[i], info, priv);
+
+	for (i = 0; i < info->num_mod_clks; i++)
+		cpg_mssr_register_mod_clk(&info->mod_clks[i], info, priv);
+
+	error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
+	if (error)
+		return error;
+
+	devm_add_action(dev, cpg_mssr_del_clk_provider, np);
+
+	error = cpg_mssr_add_clk_domain(dev, info->core_pm_clks,
+					info->num_core_pm_clks);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+static struct platform_driver cpg_mssr_driver = {
+	.driver		= {
+		.name	= "renesas-cpg-mssr",
+		.of_match_table = cpg_mssr_match,
+	},
+};
+
+static int __init cpg_mssr_init(void)
+{
+	return platform_driver_probe(&cpg_mssr_driver, cpg_mssr_probe);
+}
+
+subsys_initcall(cpg_mssr_init);
+
+MODULE_DESCRIPTION("Renesas CPG/MSSR Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/shmobile/renesas-cpg-mssr.h b/drivers/clk/shmobile/renesas-cpg-mssr.h
new file mode 100644
index 0000000..e09f03c
--- /dev/null
+++ b/drivers/clk/shmobile/renesas-cpg-mssr.h
@@ -0,0 +1,132 @@
+/*
+ * Renesas Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2015 Glider bvba
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#ifndef __CLK_RENESAS_CPG_MSSR_H__
+#define __CLK_RENESAS_CPG_MSSR_H__
+
+    /*
+     * Definitions of CPG Core Clocks
+     *
+     * These include:
+     *   - Clock outputs exported to DT
+     *   - External input clocks
+     *   - Internal CPG clocks
+     */
+
+struct cpg_core_clk {
+	/* Common */
+	const char *name;
+	unsigned int id;
+	unsigned int type;
+	/* Depending on type */
+	unsigned int parent;	/* Core Clocks only */
+	unsigned int div;
+	unsigned int mult;
+	unsigned int offset;
+};
+
+enum clk_types {
+	/* Generic */
+	CLK_TYPE_IN,		/* External Clock Input */
+	CLK_TYPE_FF,		/* Fixed Factor Clock */
+	CLK_TYPE_DIV6P1,	/* DIV6 Clock with 1 parent clock */
+
+	/* Custom definitions start here */
+	CLK_TYPE_CUSTOM,
+};
+
+#define DEF_TYPE(_name, _id, _type...)	\
+	{ .name = _name, .id = _id, .type = _type }
+#define DEF_BASE(_name, _id, _type, _parent...)	\
+	DEF_TYPE(_name, _id, _type, .parent = _parent)
+
+#define DEF_INPUT(_name, _id) \
+	DEF_TYPE(_name, _id, CLK_TYPE_IN)
+#define DEF_FIXED(_name, _id, _parent, _div, _mult)	\
+	DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult)
+#define DEF_DIV6P1(_name, _id, _parent, _offset)	\
+	DEF_BASE(_name, _id, CLK_TYPE_DIV6P1, _parent, .offset = _offset)
+
+
+    /*
+     * Definitions of Module Clocks
+     */
+
+struct mssr_mod_clk {
+	const char *name;
+	unsigned int id;
+	unsigned int parent;	/* Add MOD_CLK_BASE for Module Clocks */
+};
+
+/* Convert from sparse base-100 to packed index space */
+#define MOD_CLK_PACK(x)	((x) - ((x) / 100) * (100 - 32))
+
+#define MOD_CLK_ID(x)	(MOD_CLK_BASE + MOD_CLK_PACK(x))
+
+#define DEF_MOD(_name, _mod, _parent...)	\
+	{ .name = _name, .id = MOD_CLK_ID(_mod), .parent = _parent }
+
+
+struct device_node;
+
+    /**
+     * SoC-specific CPG/MSSR Description
+     *
+     * @core_clks: Array of Core Clock definitions
+     * @num_core_clks: Number of entries in core_clks[]
+     * @last_dt_core_clk: ID of the last Core Clock exported to DT
+     * @num_total_core_clks: Total number of Core Clocks (exported + internal)
+     *
+     * @mod_clks: Array of Module Clock definitions
+     * @num_mod_clks: Number of entries in mod_clks[]
+     * @num_hw_mod_clks: Number of Module Clocks supported by the hardware
+     *
+     * @crit_mod_clks: Array with Module Clock IDs of critical clocks that
+     *                 should not be disabled without a knowledgeable driver
+     * @num_crit_mod_clks: Number of entries in crit_mod_clks[]
+     *
+     * @core_pm_clks: Array with IDs of Core Clocks that are suitable for Power
+     *                Management, in addition to Module Clocks
+     * @num_core_pm_clks: Number of entries in core_pm_clks[]
+     *
+     * @init: Optional callback to perform SoC-specific initialization
+     * @cpg_clk_register: Optional callback to handle special Core Clock types
+     */
+
+struct cpg_mssr_info {
+	/* Core Clocks */
+	const struct cpg_core_clk *core_clks;
+	unsigned int num_core_clks;
+	unsigned int last_dt_core_clk;
+	unsigned int num_total_core_clks;
+
+	/* Module Clocks */
+	const struct mssr_mod_clk *mod_clks;
+	unsigned int num_mod_clks;
+	unsigned int num_hw_mod_clks;
+
+	/* Critical Module Clocks that should not be disabled */
+	const unsigned int *crit_mod_clks;
+	unsigned int num_crit_mod_clks;
+
+	/* Core Clocks suitable for PM, in addition to the Module Clocks */
+	const unsigned int *core_pm_clks;
+	unsigned int num_core_pm_clks;
+
+	/* Callbacks */
+	int (*init)(struct device *dev);
+	struct clk *(*cpg_clk_register)(struct device *dev,
+					const struct cpg_core_clk *core,
+					const struct cpg_mssr_info *info,
+					struct clk **clks, void __iomem *base);
+};
+
+extern const struct cpg_mssr_info r8a7795_cpg_mssr_info;
+#endif
diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c
index 576cd03..ccb324d 100644
--- a/drivers/clk/st/clkgen-fsyn.c
+++ b/drivers/clk/st/clkgen-fsyn.c
@@ -549,19 +549,20 @@
 	return 0;
 }
 
-static long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw, unsigned long rate
-		, unsigned long *prate)
+static long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw,
+					   unsigned long rate,
+					   unsigned long *prate)
 {
 	struct stm_fs params;
 
-	if (!clk_fs660c32_vco_get_params(*prate, rate, &params))
-		clk_fs660c32_vco_get_rate(*prate, &params, &rate);
+	if (clk_fs660c32_vco_get_params(*prate, rate, &params))
+		return rate;
 
-	pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n",
+	clk_fs660c32_vco_get_rate(*prate, &params, &rate);
+
+	pr_debug("%s: %s new rate %ld [ndiv=%u]\n",
 		 __func__, clk_hw_get_name(hw),
-		 rate, (unsigned int)params.sdiv,
-		 (unsigned int)params.mdiv,
-		 (unsigned int)params.pe, (unsigned int)params.nsdiv);
+		 rate, (unsigned int)params.ndiv);
 
 	return rate;
 }
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index cb4c299..3fd7901 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -7,14 +7,19 @@
 obj-y += clk-a10-hosc.o
 obj-y += clk-a10-mod1.o
 obj-y += clk-a10-pll2.o
+obj-y += clk-a10-ve.o
 obj-y += clk-a20-gmac.o
 obj-y += clk-mod0.o
 obj-y += clk-simple-gates.o
+obj-y += clk-sun8i-bus-gates.o
 obj-y += clk-sun8i-mbus.o
 obj-y += clk-sun9i-core.o
 obj-y += clk-sun9i-mmc.o
 obj-y += clk-usb.o
 
+obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
+obj-$(CONFIG_MACH_SUN9I) += clk-sun9i-cpus.o
+
 obj-$(CONFIG_MFD_SUN6I_PRCM) += \
 	clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
 	clk-sun8i-apb0.o
diff --git a/drivers/clk/sunxi/clk-a10-ve.c b/drivers/clk/sunxi/clk-a10-ve.c
new file mode 100644
index 0000000..044c171
--- /dev/null
+++ b/drivers/clk/sunxi/clk-a10-ve.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2015 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+static DEFINE_SPINLOCK(ve_lock);
+
+#define SUN4I_VE_ENABLE		31
+#define SUN4I_VE_DIVIDER_SHIFT	16
+#define SUN4I_VE_DIVIDER_WIDTH	3
+#define SUN4I_VE_RESET		0
+
+/**
+ * sunxi_ve_reset... - reset bit in ve clk registers handling
+ */
+
+struct ve_reset_data {
+	void __iomem			*reg;
+	spinlock_t			*lock;
+	struct reset_controller_dev	rcdev;
+};
+
+static int sunxi_ve_reset_assert(struct reset_controller_dev *rcdev,
+				 unsigned long id)
+{
+	struct ve_reset_data *data = container_of(rcdev,
+						  struct ve_reset_data,
+						  rcdev);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(data->lock, flags);
+
+	reg = readl(data->reg);
+	writel(reg & ~BIT(SUN4I_VE_RESET), data->reg);
+
+	spin_unlock_irqrestore(data->lock, flags);
+
+	return 0;
+}
+
+static int sunxi_ve_reset_deassert(struct reset_controller_dev *rcdev,
+				   unsigned long id)
+{
+	struct ve_reset_data *data = container_of(rcdev,
+						  struct ve_reset_data,
+						  rcdev);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(data->lock, flags);
+
+	reg = readl(data->reg);
+	writel(reg | BIT(SUN4I_VE_RESET), data->reg);
+
+	spin_unlock_irqrestore(data->lock, flags);
+
+	return 0;
+}
+
+static int sunxi_ve_of_xlate(struct reset_controller_dev *rcdev,
+			     const struct of_phandle_args *reset_spec)
+{
+	if (WARN_ON(reset_spec->args_count != 0))
+		return -EINVAL;
+
+	return 0;
+}
+
+static struct reset_control_ops sunxi_ve_reset_ops = {
+	.assert		= sunxi_ve_reset_assert,
+	.deassert	= sunxi_ve_reset_deassert,
+};
+
+static void __init sun4i_ve_clk_setup(struct device_node *node)
+{
+	struct clk *clk;
+	struct clk_divider *div;
+	struct clk_gate *gate;
+	struct ve_reset_data *reset_data;
+	const char *parent;
+	const char *clk_name = node->name;
+	void __iomem *reg;
+	int err;
+
+	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+	if (IS_ERR(reg))
+		return;
+
+	div = kzalloc(sizeof(*div), GFP_KERNEL);
+	if (!div)
+		goto err_unmap;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		goto err_free_div;
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+	parent = of_clk_get_parent_name(node, 0);
+
+	gate->reg = reg;
+	gate->bit_idx = SUN4I_VE_ENABLE;
+	gate->lock = &ve_lock;
+
+	div->reg = reg;
+	div->shift = SUN4I_VE_DIVIDER_SHIFT;
+	div->width = SUN4I_VE_DIVIDER_WIDTH;
+	div->lock = &ve_lock;
+
+	clk = clk_register_composite(NULL, clk_name, &parent, 1,
+				     NULL, NULL,
+				     &div->hw, &clk_divider_ops,
+				     &gate->hw, &clk_gate_ops,
+				     CLK_SET_RATE_PARENT);
+	if (IS_ERR(clk))
+		goto err_free_gate;
+
+	err = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	if (err)
+		goto err_unregister_clk;
+
+	reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
+	if (!reset_data)
+		goto err_del_provider;
+
+	reset_data->reg = reg;
+	reset_data->lock = &ve_lock;
+	reset_data->rcdev.nr_resets = 1;
+	reset_data->rcdev.ops = &sunxi_ve_reset_ops;
+	reset_data->rcdev.of_node = node;
+	reset_data->rcdev.of_xlate = sunxi_ve_of_xlate;
+	reset_data->rcdev.of_reset_n_cells = 0;
+	err = reset_controller_register(&reset_data->rcdev);
+	if (err)
+		goto err_free_reset;
+
+	return;
+
+err_free_reset:
+	kfree(reset_data);
+err_del_provider:
+	of_clk_del_provider(node);
+err_unregister_clk:
+	clk_unregister(clk);
+err_free_gate:
+	kfree(gate);
+err_free_div:
+	kfree(div);
+err_unmap:
+	iounmap(reg);
+}
+CLK_OF_DECLARE(sun4i_ve, "allwinner,sun4i-a10-ve-clk",
+	       sun4i_ve_clk_setup);
diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c
index 0214c65..f4da52b 100644
--- a/drivers/clk/sunxi/clk-simple-gates.c
+++ b/drivers/clk/sunxi/clk-simple-gates.c
@@ -140,6 +140,8 @@
 	       sunxi_simple_gates_init);
 CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-gates-clk",
 	       sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun9i_a80_apbs, "allwinner,sun9i-a80-apbs-gates-clk",
+	       sunxi_simple_gates_init);
 
 static const int sun4i_a10_ahb_critical_clocks[] __initconst = {
 	14,	/* ahb_sdram */
@@ -158,3 +160,15 @@
 	       sun4i_a10_ahb_init);
 CLK_OF_DECLARE(sun7i_a20_ahb, "allwinner,sun7i-a20-ahb-gates-clk",
 	       sun4i_a10_ahb_init);
+
+static const int sun4i_a10_dram_critical_clocks[] __initconst = {
+	15,	/* dram_output */
+};
+
+static void __init sun4i_a10_dram_init(struct device_node *node)
+{
+	sunxi_simple_gates_setup(node, sun4i_a10_dram_critical_clocks,
+				 ARRAY_SIZE(sun4i_a10_dram_critical_clocks));
+}
+CLK_OF_DECLARE(sun4i_a10_dram, "allwinner,sun4i-a10-dram-gates-clk",
+	       sun4i_a10_dram_init);
diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c
index 7ae5d2c..7ba6110 100644
--- a/drivers/clk/sunxi/clk-sun8i-apb0.c
+++ b/drivers/clk/sunxi/clk-sun8i-apb0.c
@@ -17,13 +17,77 @@
 #include <linux/clk-provider.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/platform_device.h>
 
+static struct clk *sun8i_a23_apb0_register(struct device_node *node,
+					   void __iomem *reg)
+{
+	const char *clk_name = node->name;
+	const char *clk_parent;
+	struct clk *clk;
+	int ret;
+
+	clk_parent = of_clk_get_parent_name(node, 0);
+	if (!clk_parent)
+		return ERR_PTR(-EINVAL);
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	/* The A23 APB0 clock is a standard 2 bit wide divider clock */
+	clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
+				   0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+	if (IS_ERR(clk))
+		return clk;
+
+	ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	if (ret)
+		goto err_unregister;
+
+	return clk;
+
+err_unregister:
+	clk_unregister_divider(clk);
+
+	return ERR_PTR(ret);
+}
+
+static void sun8i_a23_apb0_setup(struct device_node *node)
+{
+	void __iomem *reg;
+	struct resource res;
+	struct clk *clk;
+
+	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+	if (IS_ERR(reg)) {
+		/*
+		 * This happens with clk nodes instantiated through mfd,
+		 * as those do not have their resources assigned in the
+		 * device tree. Do not print an error in this case.
+		 */
+		if (PTR_ERR(reg) != -EINVAL)
+			pr_err("Could not get registers for a23-apb0-clk\n");
+
+		return;
+	}
+
+	clk = sun8i_a23_apb0_register(node, reg);
+	if (IS_ERR(clk))
+		goto err_unmap;
+
+	return;
+
+err_unmap:
+	iounmap(reg);
+	of_address_to_resource(node, 0, &res);
+	release_mem_region(res.start, resource_size(&res));
+}
+CLK_OF_DECLARE(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk",
+	       sun8i_a23_apb0_setup);
+
 static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
-	const char *clk_name = np->name;
-	const char *clk_parent;
 	struct resource *r;
 	void __iomem *reg;
 	struct clk *clk;
@@ -33,19 +97,11 @@
 	if (IS_ERR(reg))
 		return PTR_ERR(reg);
 
-	clk_parent = of_clk_get_parent_name(np, 0);
-	if (!clk_parent)
-		return -EINVAL;
-
-	of_property_read_string(np, "clock-output-names", &clk_name);
-
-	/* The A23 APB0 clock is a standard 2 bit wide divider clock */
-	clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg,
-				   0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+	clk = sun8i_a23_apb0_register(np, reg);
 	if (IS_ERR(clk))
 		return PTR_ERR(clk);
 
-	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	return 0;
 }
 
 static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = {
diff --git a/drivers/clk/sunxi/clk-sun8i-bus-gates.c b/drivers/clk/sunxi/clk-sun8i-bus-gates.c
new file mode 100644
index 0000000..e32d18b
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun8i-bus-gates.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
+ *
+ * Based on clk-simple-gates.c, which is:
+ * Copyright 2015 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+static DEFINE_SPINLOCK(gates_lock);
+
+static void __init sun8i_h3_bus_gates_init(struct device_node *node)
+{
+	static const char * const names[] = { "ahb1", "ahb2", "apb1", "apb2" };
+	enum { AHB1, AHB2, APB1, APB2, PARENT_MAX } clk_parent;
+	const char *parents[PARENT_MAX];
+	struct clk_onecell_data *clk_data;
+	const char *clk_name;
+	struct property *prop;
+	struct resource res;
+	void __iomem *clk_reg;
+	void __iomem *reg;
+	const __be32 *p;
+	int number, i;
+	u8 clk_bit;
+	int index;
+
+	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+	if (IS_ERR(reg))
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(names); i++) {
+		int idx = of_property_match_string(node, "clock-names",
+						   names[i]);
+		if (idx < 0)
+			return;
+
+		parents[i] = of_clk_get_parent_name(node, idx);
+	}
+
+	clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
+	if (!clk_data)
+		goto err_unmap;
+
+	number = of_property_count_u32_elems(node, "clock-indices");
+	of_property_read_u32_index(node, "clock-indices", number - 1, &number);
+
+	clk_data->clks = kcalloc(number + 1, sizeof(struct clk *), GFP_KERNEL);
+	if (!clk_data->clks)
+		goto err_free_data;
+
+	i = 0;
+	of_property_for_each_u32(node, "clock-indices", prop, p, index) {
+		of_property_read_string_index(node, "clock-output-names",
+					      i, &clk_name);
+
+		if (index == 17 || (index >= 29 && index <= 31))
+			clk_parent = AHB2;
+		else if (index <= 63 || index >= 128)
+			clk_parent = AHB1;
+		else if (index >= 64 && index <= 95)
+			clk_parent = APB1;
+		else if (index >= 96 && index <= 127)
+			clk_parent = APB2;
+
+		clk_reg = reg + 4 * (index / 32);
+		clk_bit = index % 32;
+
+		clk_data->clks[index] = clk_register_gate(NULL, clk_name,
+							  parents[clk_parent],
+							  0, clk_reg, clk_bit,
+							  0, &gates_lock);
+		i++;
+
+		if (IS_ERR(clk_data->clks[index])) {
+			WARN_ON(true);
+			continue;
+		}
+	}
+
+	clk_data->clk_num = number + 1;
+	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+	return;
+
+err_free_data:
+	kfree(clk_data);
+err_unmap:
+	iounmap(reg);
+	of_address_to_resource(node, 0, &res);
+	release_mem_region(res.start, resource_size(&res));
+}
+
+CLK_OF_DECLARE(sun8i_h3_bus_gates, "allwinner,sun8i-h3-bus-gates-clk",
+	       sun8i_h3_bus_gates_init);
diff --git a/drivers/clk/sunxi/clk-sun9i-cpus.c b/drivers/clk/sunxi/clk-sun9i-cpus.c
new file mode 100644
index 0000000..7626d21
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun9i-cpus.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2015 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * Allwinner A80 CPUS clock driver
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+static DEFINE_SPINLOCK(sun9i_a80_cpus_lock);
+
+/**
+ * sun9i_a80_cpus_clk_setup() - Setup function for a80 cpus composite clk
+ */
+
+#define SUN9I_CPUS_MAX_PARENTS		4
+#define SUN9I_CPUS_MUX_PARENT_PLL4	3
+#define SUN9I_CPUS_MUX_SHIFT		16
+#define SUN9I_CPUS_MUX_MASK		GENMASK(17, 16)
+#define SUN9I_CPUS_MUX_GET_PARENT(reg)	((reg & SUN9I_CPUS_MUX_MASK) >> \
+						SUN9I_CPUS_MUX_SHIFT)
+
+#define SUN9I_CPUS_DIV_SHIFT		4
+#define SUN9I_CPUS_DIV_MASK		GENMASK(5, 4)
+#define SUN9I_CPUS_DIV_GET(reg)		((reg & SUN9I_CPUS_DIV_MASK) >> \
+						SUN9I_CPUS_DIV_SHIFT)
+#define SUN9I_CPUS_DIV_SET(reg, div)	((reg & ~SUN9I_CPUS_DIV_MASK) | \
+						(div << SUN9I_CPUS_DIV_SHIFT))
+#define SUN9I_CPUS_PLL4_DIV_SHIFT	8
+#define SUN9I_CPUS_PLL4_DIV_MASK	GENMASK(12, 8)
+#define SUN9I_CPUS_PLL4_DIV_GET(reg)	((reg & SUN9I_CPUS_PLL4_DIV_MASK) >> \
+						SUN9I_CPUS_PLL4_DIV_SHIFT)
+#define SUN9I_CPUS_PLL4_DIV_SET(reg, div) ((reg & ~SUN9I_CPUS_PLL4_DIV_MASK) | \
+						(div << SUN9I_CPUS_PLL4_DIV_SHIFT))
+
+struct sun9i_a80_cpus_clk {
+	struct clk_hw hw;
+	void __iomem *reg;
+};
+
+#define to_sun9i_a80_cpus_clk(_hw) container_of(_hw, struct sun9i_a80_cpus_clk, hw)
+
+static unsigned long sun9i_a80_cpus_clk_recalc_rate(struct clk_hw *hw,
+						    unsigned long parent_rate)
+{
+	struct sun9i_a80_cpus_clk *cpus = to_sun9i_a80_cpus_clk(hw);
+	unsigned long rate;
+	u32 reg;
+
+	/* Fetch the register value */
+	reg = readl(cpus->reg);
+
+	/* apply pre-divider first if parent is pll4 */
+	if (SUN9I_CPUS_MUX_GET_PARENT(reg) == SUN9I_CPUS_MUX_PARENT_PLL4)
+		parent_rate /= SUN9I_CPUS_PLL4_DIV_GET(reg) + 1;
+
+	/* clk divider */
+	rate = parent_rate / (SUN9I_CPUS_DIV_GET(reg) + 1);
+
+	return rate;
+}
+
+static long sun9i_a80_cpus_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
+				     u8 parent, unsigned long parent_rate)
+{
+	u8 div, pre_div = 1;
+
+	/*
+	 * clock can only divide, so we will never be able to achieve
+	 * frequencies higher than the parent frequency
+	 */
+	if (parent_rate && rate > parent_rate)
+		rate = parent_rate;
+
+	div = DIV_ROUND_UP(parent_rate, rate);
+
+	/* calculate pre-divider if parent is pll4 */
+	if (parent == SUN9I_CPUS_MUX_PARENT_PLL4 && div > 4) {
+		/* pre-divider is 1 ~ 32 */
+		if (div < 32) {
+			pre_div = div;
+			div = 1;
+		} else if (div < 64) {
+			pre_div = DIV_ROUND_UP(div, 2);
+			div = 2;
+		} else if (div < 96) {
+			pre_div = DIV_ROUND_UP(div, 3);
+			div = 3;
+		} else {
+			pre_div = DIV_ROUND_UP(div, 4);
+			div = 4;
+		}
+	}
+
+	/* we were asked to pass back divider values */
+	if (divp) {
+		*divp = div - 1;
+		*pre_divp = pre_div - 1;
+	}
+
+	return parent_rate / pre_div / div;
+}
+
+static int sun9i_a80_cpus_clk_determine_rate(struct clk_hw *clk,
+					     struct clk_rate_request *req)
+{
+	struct clk_hw *parent, *best_parent = NULL;
+	int i, num_parents;
+	unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
+	unsigned long rate = req->rate;
+
+	/* find the parent that can help provide the fastest rate <= rate */
+	num_parents = clk_hw_get_num_parents(clk);
+	for (i = 0; i < num_parents; i++) {
+		parent = clk_hw_get_parent_by_index(clk, i);
+		if (!parent)
+			continue;
+		if (clk_hw_get_flags(clk) & CLK_SET_RATE_PARENT)
+			parent_rate = clk_hw_round_rate(parent, rate);
+		else
+			parent_rate = clk_hw_get_rate(parent);
+
+		child_rate = sun9i_a80_cpus_clk_round(rate, NULL, NULL, i,
+						      parent_rate);
+
+		if (child_rate <= rate && child_rate > best_child_rate) {
+			best_parent = parent;
+			best = parent_rate;
+			best_child_rate = child_rate;
+		}
+	}
+
+	if (!best_parent)
+		return -EINVAL;
+
+	req->best_parent_hw = best_parent;
+	req->best_parent_rate = best;
+	req->rate = best_child_rate;
+
+	return 0;
+}
+
+static int sun9i_a80_cpus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+				       unsigned long parent_rate)
+{
+	struct sun9i_a80_cpus_clk *cpus = to_sun9i_a80_cpus_clk(hw);
+	unsigned long flags;
+	u8 div, pre_div, parent;
+	u32 reg;
+
+	spin_lock_irqsave(&sun9i_a80_cpus_lock, flags);
+
+	reg = readl(cpus->reg);
+
+	/* need to know which parent is used to apply pre-divider */
+	parent = SUN9I_CPUS_MUX_GET_PARENT(reg);
+	sun9i_a80_cpus_clk_round(rate, &div, &pre_div, parent, parent_rate);
+
+	reg = SUN9I_CPUS_DIV_SET(reg, div);
+	reg = SUN9I_CPUS_PLL4_DIV_SET(reg, pre_div);
+	writel(reg, cpus->reg);
+
+	spin_unlock_irqrestore(&sun9i_a80_cpus_lock, flags);
+
+	return 0;
+}
+
+static const struct clk_ops sun9i_a80_cpus_clk_ops = {
+	.determine_rate	= sun9i_a80_cpus_clk_determine_rate,
+	.recalc_rate	= sun9i_a80_cpus_clk_recalc_rate,
+	.set_rate	= sun9i_a80_cpus_clk_set_rate,
+};
+
+static void sun9i_a80_cpus_setup(struct device_node *node)
+{
+	const char *clk_name = node->name;
+	const char *parents[SUN9I_CPUS_MAX_PARENTS];
+	struct resource res;
+	struct sun9i_a80_cpus_clk *cpus;
+	struct clk_mux *mux;
+	struct clk *clk;
+	int ret;
+
+	cpus = kzalloc(sizeof(*cpus), GFP_KERNEL);
+	if (!cpus)
+		return;
+
+	cpus->reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+	if (IS_ERR(cpus->reg))
+		goto err_free_cpus;
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	/* we have a mux, we will have >1 parents */
+	ret = of_clk_parent_fill(node, parents, SUN9I_CPUS_MAX_PARENTS);
+
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		goto err_unmap;
+
+	/* set up clock properties */
+	mux->reg = cpus->reg;
+	mux->shift = SUN9I_CPUS_MUX_SHIFT;
+	/* un-shifted mask is what mux_clk expects */
+	mux->mask = SUN9I_CPUS_MUX_MASK >> SUN9I_CPUS_MUX_SHIFT;
+	mux->lock = &sun9i_a80_cpus_lock;
+
+	clk = clk_register_composite(NULL, clk_name, parents, ret,
+				     &mux->hw, &clk_mux_ops,
+				     &cpus->hw, &sun9i_a80_cpus_clk_ops,
+				     NULL, NULL, 0);
+	if (IS_ERR(clk))
+		goto err_free_mux;
+
+	ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	if (ret)
+		goto err_unregister;
+
+	return;
+
+err_unregister:
+	clk_unregister(clk);
+err_free_mux:
+	kfree(mux);
+err_unmap:
+	iounmap(cpus->reg);
+	of_address_to_resource(node, 0, &res);
+	release_mem_region(res.start, resource_size(&res));
+err_free_cpus:
+	kfree(cpus);
+}
+CLK_OF_DECLARE(sun9i_a80_cpus, "allwinner,sun9i-a80-cpus-clk",
+	       sun9i_a80_cpus_setup);
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 9c79af0c..5ba2188 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -778,6 +778,10 @@
 	.shift = 12,
 };
 
+static const struct mux_data sun8i_h3_ahb2_mux_data __initconst = {
+	.shift = 0,
+};
+
 static void __init sunxi_mux_clk_setup(struct device_node *node,
 				       struct mux_data *data)
 {
@@ -1130,6 +1134,7 @@
 static const struct of_device_id clk_mux_match[] __initconst = {
 	{.compatible = "allwinner,sun4i-a10-cpu-clk", .data = &sun4i_cpu_mux_data,},
 	{.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,},
+	{.compatible = "allwinner,sun8i-h3-ahb2-clk", .data = &sun8i_h3_ahb2_mux_data,},
 	{}
 };
 
@@ -1212,6 +1217,7 @@
 CLK_OF_DECLARE(sun6i_a31s_clk_init, "allwinner,sun6i-a31s", sun6i_init_clocks);
 CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks);
 CLK_OF_DECLARE(sun8i_a33_clk_init, "allwinner,sun8i-a33", sun6i_init_clocks);
+CLK_OF_DECLARE(sun8i_h3_clk_init, "allwinner,sun8i-h3", sun6i_init_clocks);
 
 static void __init sun9i_init_clocks(struct device_node *node)
 {
diff --git a/drivers/clk/sunxi/clk-usb.c b/drivers/clk/sunxi/clk-usb.c
index 1a72cd6..67b8e38 100644
--- a/drivers/clk/sunxi/clk-usb.c
+++ b/drivers/clk/sunxi/clk-usb.c
@@ -243,3 +243,15 @@
 	sunxi_usb_clk_setup(node, &sun9i_a80_usb_phy_data, &a80_usb_phy_lock);
 }
 CLK_OF_DECLARE(sun9i_a80_usb_phy, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup);
+
+static const struct usb_clk_data sun8i_h3_usb_clk_data __initconst = {
+	.clk_mask =  BIT(19) | BIT(18) | BIT(17) | BIT(16) |
+		     BIT(11) | BIT(10) | BIT(9) | BIT(8),
+	.reset_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
+};
+
+static void __init sun8i_h3_usb_setup(struct device_node *node)
+{
+	sunxi_usb_clk_setup(node, &sun8i_h3_usb_clk_data, &sun4i_a10_usb_lock);
+}
+CLK_OF_DECLARE(sun8i_h3_usb, "allwinner,sun8i-h3-usb-clk", sun8i_h3_usb_setup);
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
index 826c325..97984c5 100644
--- a/drivers/clk/tegra/Makefile
+++ b/drivers/clk/tegra/Makefile
@@ -20,3 +20,4 @@
 obj-$(CONFIG_ARCH_TEGRA_124_SOC)	+= clk-tegra124-dfll-fcpu.o
 obj-$(CONFIG_ARCH_TEGRA_132_SOC)	+= clk-tegra124.o
 obj-y					+= cvb.o
+obj-$(CONFIG_ARCH_TEGRA_210_SOC)	+= clk-tegra210.o
diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h
index 60738cc..19ce073 100644
--- a/drivers/clk/tegra/clk-id.h
+++ b/drivers/clk/tegra/clk-id.h
@@ -13,6 +13,7 @@
 	tegra_clk_amx1,
 	tegra_clk_apbdma,
 	tegra_clk_apbif,
+	tegra_clk_ape,
 	tegra_clk_audio0,
 	tegra_clk_audio0_2x,
 	tegra_clk_audio0_mux,
@@ -38,6 +39,7 @@
 	tegra_clk_cile,
 	tegra_clk_clk_32k,
 	tegra_clk_clk72Mhz,
+	tegra_clk_clk72Mhz_8,
 	tegra_clk_clk_m,
 	tegra_clk_clk_m_div2,
 	tegra_clk_clk_m_div4,
@@ -51,17 +53,21 @@
 	tegra_clk_cml1,
 	tegra_clk_csi,
 	tegra_clk_csite,
+	tegra_clk_csite_8,
 	tegra_clk_csus,
 	tegra_clk_cve,
 	tegra_clk_dam0,
 	tegra_clk_dam1,
 	tegra_clk_dam2,
 	tegra_clk_d_audio,
+	tegra_clk_dbgapb,
 	tegra_clk_dds,
 	tegra_clk_dfll_ref,
 	tegra_clk_dfll_soc,
 	tegra_clk_disp1,
+	tegra_clk_disp1_8,
 	tegra_clk_disp2,
+	tegra_clk_disp2_8,
 	tegra_clk_dp2,
 	tegra_clk_dpaux,
 	tegra_clk_dsialp,
@@ -71,6 +77,7 @@
 	tegra_clk_dtv,
 	tegra_clk_emc,
 	tegra_clk_entropy,
+	tegra_clk_entropy_8,
 	tegra_clk_epp,
 	tegra_clk_epp_8,
 	tegra_clk_extern1,
@@ -85,12 +92,16 @@
 	tegra_clk_gr3d_8,
 	tegra_clk_hclk,
 	tegra_clk_hda,
+	tegra_clk_hda_8,
 	tegra_clk_hda2codec_2x,
+	tegra_clk_hda2codec_2x_8,
 	tegra_clk_hda2hdmi,
 	tegra_clk_hdmi,
 	tegra_clk_hdmi_audio,
 	tegra_clk_host1x,
 	tegra_clk_host1x_8,
+	tegra_clk_host1x_9,
+	tegra_clk_hsic_trk,
 	tegra_clk_i2c1,
 	tegra_clk_i2c2,
 	tegra_clk_i2c3,
@@ -110,11 +121,14 @@
 	tegra_clk_i2s4_sync,
 	tegra_clk_isp,
 	tegra_clk_isp_8,
+	tegra_clk_isp_9,
 	tegra_clk_ispb,
 	tegra_clk_kbc,
 	tegra_clk_kfuse,
 	tegra_clk_la,
+	tegra_clk_maud,
 	tegra_clk_mipi,
+	tegra_clk_mipibif,
 	tegra_clk_mipi_cal,
 	tegra_clk_mpe,
 	tegra_clk_mselect,
@@ -124,15 +138,24 @@
 	tegra_clk_ndspeed,
 	tegra_clk_ndspeed_8,
 	tegra_clk_nor,
+	tegra_clk_nvdec,
+	tegra_clk_nvenc,
+	tegra_clk_nvjpg,
 	tegra_clk_owr,
+	tegra_clk_owr_8,
 	tegra_clk_pcie,
 	tegra_clk_pclk,
 	tegra_clk_pll_a,
 	tegra_clk_pll_a_out0,
+	tegra_clk_pll_a1,
 	tegra_clk_pll_c,
 	tegra_clk_pll_c2,
 	tegra_clk_pll_c3,
 	tegra_clk_pll_c4,
+	tegra_clk_pll_c4_out0,
+	tegra_clk_pll_c4_out1,
+	tegra_clk_pll_c4_out2,
+	tegra_clk_pll_c4_out3,
 	tegra_clk_pll_c_out1,
 	tegra_clk_pll_d,
 	tegra_clk_pll_d2,
@@ -140,19 +163,29 @@
 	tegra_clk_pll_d_out0,
 	tegra_clk_pll_dp,
 	tegra_clk_pll_e_out0,
+	tegra_clk_pll_g_ref,
 	tegra_clk_pll_m,
 	tegra_clk_pll_m_out1,
+	tegra_clk_pll_mb,
 	tegra_clk_pll_p,
 	tegra_clk_pll_p_out1,
 	tegra_clk_pll_p_out2,
 	tegra_clk_pll_p_out2_int,
 	tegra_clk_pll_p_out3,
 	tegra_clk_pll_p_out4,
+	tegra_clk_pll_p_out4_cpu,
 	tegra_clk_pll_p_out5,
+	tegra_clk_pll_p_out_hsio,
+	tegra_clk_pll_p_out_xusb,
+	tegra_clk_pll_p_out_cpu,
+	tegra_clk_pll_p_out_adsp,
 	tegra_clk_pll_ref,
 	tegra_clk_pll_re_out,
 	tegra_clk_pll_re_vco,
 	tegra_clk_pll_u,
+	tegra_clk_pll_u_out,
+	tegra_clk_pll_u_out1,
+	tegra_clk_pll_u_out2,
 	tegra_clk_pll_u_12m,
 	tegra_clk_pll_u_480m,
 	tegra_clk_pll_u_48m,
@@ -160,53 +193,80 @@
 	tegra_clk_pll_x,
 	tegra_clk_pll_x_out0,
 	tegra_clk_pwm,
+	tegra_clk_qspi,
 	tegra_clk_rtc,
 	tegra_clk_sata,
+	tegra_clk_sata_8,
 	tegra_clk_sata_cold,
 	tegra_clk_sata_oob,
+	tegra_clk_sata_oob_8,
 	tegra_clk_sbc1,
 	tegra_clk_sbc1_8,
+	tegra_clk_sbc1_9,
 	tegra_clk_sbc2,
 	tegra_clk_sbc2_8,
+	tegra_clk_sbc2_9,
 	tegra_clk_sbc3,
 	tegra_clk_sbc3_8,
+	tegra_clk_sbc3_9,
 	tegra_clk_sbc4,
 	tegra_clk_sbc4_8,
+	tegra_clk_sbc4_9,
 	tegra_clk_sbc5,
 	tegra_clk_sbc5_8,
 	tegra_clk_sbc6,
 	tegra_clk_sbc6_8,
 	tegra_clk_sclk,
+	tegra_clk_sdmmc_legacy,
 	tegra_clk_sdmmc1,
 	tegra_clk_sdmmc1_8,
+	tegra_clk_sdmmc1_9,
 	tegra_clk_sdmmc2,
 	tegra_clk_sdmmc2_8,
+	tegra_clk_sdmmc2_9,
 	tegra_clk_sdmmc3,
 	tegra_clk_sdmmc3_8,
+	tegra_clk_sdmmc3_9,
 	tegra_clk_sdmmc4,
 	tegra_clk_sdmmc4_8,
+	tegra_clk_sdmmc4_9,
 	tegra_clk_se,
 	tegra_clk_soc_therm,
+	tegra_clk_soc_therm_8,
 	tegra_clk_sor0,
 	tegra_clk_sor0_lvds,
+	tegra_clk_sor1,
+	tegra_clk_sor1_brick,
+	tegra_clk_sor1_src,
 	tegra_clk_spdif,
 	tegra_clk_spdif_2x,
 	tegra_clk_spdif_in,
+	tegra_clk_spdif_in_8,
 	tegra_clk_spdif_in_sync,
 	tegra_clk_spdif_mux,
 	tegra_clk_spdif_out,
 	tegra_clk_timer,
 	tegra_clk_trace,
 	tegra_clk_tsec,
+	tegra_clk_tsec_8,
+	tegra_clk_tsecb,
 	tegra_clk_tsensor,
 	tegra_clk_tvdac,
 	tegra_clk_tvo,
 	tegra_clk_uarta,
+	tegra_clk_uarta_8,
 	tegra_clk_uartb,
+	tegra_clk_uartb_8,
 	tegra_clk_uartc,
+	tegra_clk_uartc_8,
 	tegra_clk_uartd,
+	tegra_clk_uartd_8,
 	tegra_clk_uarte,
+	tegra_clk_uarte_8,
+	tegra_clk_uartape,
 	tegra_clk_usb2,
+	tegra_clk_usb2_hsic_trk,
+	tegra_clk_usb2_trk,
 	tegra_clk_usb3,
 	tegra_clk_usbd,
 	tegra_clk_vcp,
@@ -216,22 +276,35 @@
 	tegra_clk_vi,
 	tegra_clk_vi_8,
 	tegra_clk_vi_9,
+	tegra_clk_vi_10,
+	tegra_clk_vi_i2c,
 	tegra_clk_vic03,
+	tegra_clk_vic03_8,
 	tegra_clk_vim2_clk,
 	tegra_clk_vimclk_sync,
 	tegra_clk_vi_sensor,
-	tegra_clk_vi_sensor2,
 	tegra_clk_vi_sensor_8,
+	tegra_clk_vi_sensor_9,
+	tegra_clk_vi_sensor2,
+	tegra_clk_vi_sensor2_8,
 	tegra_clk_xusb_dev,
 	tegra_clk_xusb_dev_src,
+	tegra_clk_xusb_dev_src_8,
 	tegra_clk_xusb_falcon_src,
+	tegra_clk_xusb_falcon_src_8,
 	tegra_clk_xusb_fs_src,
+	tegra_clk_xusb_gate,
 	tegra_clk_xusb_host,
 	tegra_clk_xusb_host_src,
+	tegra_clk_xusb_host_src_8,
 	tegra_clk_xusb_hs_src,
+	tegra_clk_xusb_hs_src_4,
 	tegra_clk_xusb_ss,
 	tegra_clk_xusb_ss_src,
+	tegra_clk_xusb_ss_src_8,
 	tegra_clk_xusb_ss_div2,
+	tegra_clk_xusb_ssp_src,
+	tegra_clk_sclk_mux,
 	tegra_clk_max,
 };
 
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index d6d4ecb..a534bfa 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -65,6 +65,7 @@
 #define PLLE_BASE_DIVN_WIDTH 8
 #define PLLE_BASE_DIVM_SHIFT 0
 #define PLLE_BASE_DIVM_WIDTH 8
+#define PLLE_BASE_ENABLE BIT(31)
 
 #define PLLE_MISC_SETUP_BASE_SHIFT 16
 #define PLLE_MISC_SETUP_BASE_MASK (0xffff << PLLE_MISC_SETUP_BASE_SHIFT)
@@ -102,6 +103,7 @@
 #define PLLE_AUX_SEQ_ENABLE	BIT(24)
 #define PLLE_AUX_SEQ_START_STATE BIT(25)
 #define PLLE_AUX_PLLRE_SEL	BIT(28)
+#define PLLE_AUX_SS_SEQ_INCLUDE	BIT(31)
 
 #define XUSBIO_PLL_CFG0		0x51c
 #define XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL	BIT(0)
@@ -187,17 +189,23 @@
 #define pll_readl_base(p) pll_readl(p->params->base_reg, p)
 #define pll_readl_misc(p) pll_readl(p->params->misc_reg, p)
 #define pll_override_readl(offset, p) readl_relaxed(p->pmc + offset)
+#define pll_readl_sdm_din(p) pll_readl(p->params->sdm_din_reg, p)
+#define pll_readl_sdm_ctrl(p) pll_readl(p->params->sdm_ctrl_reg, p)
 
 #define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset)
 #define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p)
 #define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p)
 #define pll_override_writel(val, offset, p) writel(val, p->pmc + offset)
+#define pll_writel_sdm_din(val, p) pll_writel(val, p->params->sdm_din_reg, p)
+#define pll_writel_sdm_ctrl(val, p) pll_writel(val, p->params->sdm_ctrl_reg, p)
 
 #define mask(w) ((1 << (w)) - 1)
 #define divm_mask(p) mask(p->params->div_nmp->divm_width)
 #define divn_mask(p) mask(p->params->div_nmp->divn_width)
 #define divp_mask(p) (p->params->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK :\
 		      mask(p->params->div_nmp->divp_width))
+#define sdm_din_mask(p) p->params->sdm_din_mask
+#define sdm_en_mask(p) p->params->sdm_ctrl_en_mask
 
 #define divm_shift(p) (p)->params->div_nmp->divm_shift
 #define divn_shift(p) (p)->params->div_nmp->divn_shift
@@ -211,6 +219,9 @@
 #define divn_max(p) (divn_mask(p))
 #define divp_max(p) (1 << (divp_mask(p)))
 
+#define sdin_din_to_data(din)	((u16)((din) ? : 0xFFFFU))
+#define sdin_data_to_din(dat)	(((dat) == 0xFFFFU) ? 0 : (s16)dat)
+
 static struct div_nmp default_nmp = {
 	.divn_shift = PLL_BASE_DIVN_SHIFT,
 	.divn_width = PLL_BASE_DIVN_WIDTH,
@@ -269,6 +280,11 @@
 	return -1;
 }
 
+int tegra_pll_wait_for_lock(struct tegra_clk_pll *pll)
+{
+	return clk_pll_wait_for_lock(pll);
+}
+
 static int clk_pll_is_enabled(struct clk_hw *hw)
 {
 	struct tegra_clk_pll *pll = to_clk_pll(hw);
@@ -290,6 +306,19 @@
 	struct tegra_clk_pll *pll = to_clk_pll(hw);
 	u32 val;
 
+	if (pll->params->iddq_reg) {
+		val = pll_readl(pll->params->iddq_reg, pll);
+		val &= ~BIT(pll->params->iddq_bit_idx);
+		pll_writel(val, pll->params->iddq_reg, pll);
+		udelay(2);
+	}
+
+	if (pll->params->reset_reg) {
+		val = pll_readl(pll->params->reset_reg, pll);
+		val &= ~BIT(pll->params->reset_bit_idx);
+		pll_writel(val, pll->params->reset_reg, pll);
+	}
+
 	clk_pll_enable_lock(pll);
 
 	val = pll_readl_base(pll);
@@ -321,6 +350,19 @@
 		val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
 		writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE);
 	}
+
+	if (pll->params->reset_reg) {
+		val = pll_readl(pll->params->reset_reg, pll);
+		val |= BIT(pll->params->reset_bit_idx);
+		pll_writel(val, pll->params->reset_reg, pll);
+	}
+
+	if (pll->params->iddq_reg) {
+		val = pll_readl(pll->params->iddq_reg, pll);
+		val |= BIT(pll->params->iddq_bit_idx);
+		pll_writel(val, pll->params->iddq_reg, pll);
+		udelay(2);
+	}
 }
 
 static int clk_pll_enable(struct clk_hw *hw)
@@ -359,7 +401,7 @@
 static int _p_div_to_hw(struct clk_hw *hw, u8 p_div)
 {
 	struct tegra_clk_pll *pll = to_clk_pll(hw);
-	struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
+	const struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
 
 	if (p_tohw) {
 		while (p_tohw->pdiv) {
@@ -372,10 +414,15 @@
 	return -EINVAL;
 }
 
+int tegra_pll_p_div_to_hw(struct tegra_clk_pll *pll, u8 p_div)
+{
+	return _p_div_to_hw(&pll->hw, p_div);
+}
+
 static int _hw_to_p_div(struct clk_hw *hw, u8 p_div_hw)
 {
 	struct tegra_clk_pll *pll = to_clk_pll(hw);
-	struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
+	const struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
 
 	if (p_tohw) {
 		while (p_tohw->pdiv) {
@@ -395,6 +442,7 @@
 {
 	struct tegra_clk_pll *pll = to_clk_pll(hw);
 	struct tegra_clk_pll_freq_table *sel;
+	int p;
 
 	for (sel = pll->params->freq_table; sel->input_rate != 0; sel++)
 		if (sel->input_rate == parent_rate &&
@@ -404,12 +452,21 @@
 	if (sel->input_rate == 0)
 		return -EINVAL;
 
+	if (pll->params->pdiv_tohw) {
+		p = _p_div_to_hw(hw, sel->p);
+		if (p < 0)
+			return p;
+	} else {
+		p = ilog2(sel->p);
+	}
+
 	cfg->input_rate = sel->input_rate;
 	cfg->output_rate = sel->output_rate;
 	cfg->m = sel->m;
 	cfg->n = sel->n;
-	cfg->p = sel->p;
+	cfg->p = p;
 	cfg->cpcon = sel->cpcon;
+	cfg->sdm_data = sel->sdm_data;
 
 	return 0;
 }
@@ -439,7 +496,7 @@
 		/*
 		 * PLL_P_OUT1 rate is not listed in PLLA table
 		 */
-		cfreq = parent_rate/(parent_rate/1000000);
+		cfreq = parent_rate / (parent_rate / 1000000);
 		break;
 	default:
 		pr_err("%s Unexpected reference rate %lu\n",
@@ -476,6 +533,42 @@
 	return 0;
 }
 
+/*
+ * SDM (Sigma Delta Modulator) divisor is 16-bit 2's complement signed number
+ * within (-2^12 ... 2^12-1) range. Represented in PLL data structure as
+ * unsigned 16-bit value, with "0" divisor mapped to 0xFFFF. Data "0" is used
+ * to indicate that SDM is disabled.
+ *
+ * Effective ndiv value when SDM is enabled: ndiv + 1/2 + sdm_din/2^13
+ */
+static void clk_pll_set_sdm_data(struct clk_hw *hw,
+				 struct tegra_clk_pll_freq_table *cfg)
+{
+	struct tegra_clk_pll *pll = to_clk_pll(hw);
+	u32 val;
+	bool enabled;
+
+	if (!pll->params->sdm_din_reg)
+		return;
+
+	if (cfg->sdm_data) {
+		val = pll_readl_sdm_din(pll) & (~sdm_din_mask(pll));
+		val |= sdin_data_to_din(cfg->sdm_data) & sdm_din_mask(pll);
+		pll_writel_sdm_din(val, pll);
+	}
+
+	val = pll_readl_sdm_ctrl(pll);
+	enabled = (val & sdm_en_mask(pll));
+
+	if (cfg->sdm_data == 0 && enabled)
+		val &= ~pll->params->sdm_ctrl_en_mask;
+
+	if (cfg->sdm_data != 0 && !enabled)
+		val |= pll->params->sdm_ctrl_en_mask;
+
+	pll_writel_sdm_ctrl(val, pll);
+}
+
 static void _update_pll_mnp(struct tegra_clk_pll *pll,
 			    struct tegra_clk_pll_freq_table *cfg)
 {
@@ -483,7 +576,7 @@
 	struct tegra_clk_pll_params *params = pll->params;
 	struct div_nmp *div_nmp = params->div_nmp;
 
-	if ((params->flags & TEGRA_PLLM) &&
+	if ((params->flags & (TEGRA_PLLM | TEGRA_PLLMB)) &&
 		(pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) &
 			PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) {
 		val = pll_override_readl(params->pmc_divp_reg, pll);
@@ -508,6 +601,8 @@
 		       (cfg->p << divp_shift(pll));
 
 		pll_writel_base(val, pll);
+
+		clk_pll_set_sdm_data(&pll->hw, cfg);
 	}
 }
 
@@ -518,7 +613,7 @@
 	struct tegra_clk_pll_params *params = pll->params;
 	struct div_nmp *div_nmp = params->div_nmp;
 
-	if ((params->flags & TEGRA_PLLM) &&
+	if ((params->flags & (TEGRA_PLLM | TEGRA_PLLMB)) &&
 		(pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) &
 			PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) {
 		val = pll_override_readl(params->pmc_divp_reg, pll);
@@ -533,6 +628,14 @@
 		cfg->m = (val >> div_nmp->divm_shift) & divm_mask(pll);
 		cfg->n = (val >> div_nmp->divn_shift) & divn_mask(pll);
 		cfg->p = (val >> div_nmp->divp_shift) & divp_mask(pll);
+
+		if (pll->params->sdm_din_reg) {
+			if (sdm_en_mask(pll) & pll_readl_sdm_ctrl(pll)) {
+				val = pll_readl_sdm_din(pll);
+				val &= sdm_din_mask(pll);
+				cfg->sdm_data = sdin_din_to_data(val);
+			}
+		}
 	}
 }
 
@@ -560,16 +663,51 @@
 	pll_writel_misc(val, pll);
 }
 
+static void pll_clk_start_ss(struct tegra_clk_pll *pll)
+{
+	if (pll->params->defaults_set && pll->params->ssc_ctrl_reg) {
+		u32 val = pll_readl(pll->params->ssc_ctrl_reg, pll);
+
+		val |= pll->params->ssc_ctrl_en_mask;
+		pll_writel(val, pll->params->ssc_ctrl_reg, pll);
+	}
+}
+
+static void pll_clk_stop_ss(struct tegra_clk_pll *pll)
+{
+	if (pll->params->defaults_set && pll->params->ssc_ctrl_reg) {
+		u32 val = pll_readl(pll->params->ssc_ctrl_reg, pll);
+
+		val &= ~pll->params->ssc_ctrl_en_mask;
+		pll_writel(val, pll->params->ssc_ctrl_reg, pll);
+	}
+}
+
 static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
 			unsigned long rate)
 {
 	struct tegra_clk_pll *pll = to_clk_pll(hw);
+	struct tegra_clk_pll_freq_table old_cfg;
 	int state, ret = 0;
 
 	state = clk_pll_is_enabled(hw);
 
-	if (state)
+	_get_pll_mnp(pll, &old_cfg);
+
+	if (state && pll->params->defaults_set && pll->params->dyn_ramp &&
+			(cfg->m == old_cfg.m) && (cfg->p == old_cfg.p)) {
+		ret = pll->params->dyn_ramp(pll, cfg);
+		if (!ret)
+			return 0;
+	}
+
+	if (state) {
+		pll_clk_stop_ss(pll);
 		_clk_pll_disable(hw);
+	}
+
+	if (!pll->params->defaults_set && pll->params->set_defaults)
+		pll->params->set_defaults(pll);
 
 	_update_pll_mnp(pll, cfg);
 
@@ -579,6 +717,7 @@
 	if (state) {
 		_clk_pll_enable(hw);
 		ret = clk_pll_wait_for_lock(pll);
+		pll_clk_start_ss(pll);
 	}
 
 	return ret;
@@ -603,7 +742,7 @@
 	}
 
 	if (_get_table_rate(hw, &cfg, rate, parent_rate) &&
-	    _calc_rate(hw, &cfg, rate, parent_rate)) {
+	    pll->params->calc_rate(hw, &cfg, rate, parent_rate)) {
 		pr_err("%s: Failed to set %s rate %lu\n", __func__,
 		       clk_hw_get_name(hw), rate);
 		WARN_ON(1);
@@ -613,8 +752,11 @@
 		spin_lock_irqsave(pll->lock, flags);
 
 	_get_pll_mnp(pll, &old_cfg);
+	if (pll->params->flags & TEGRA_PLL_VCO_OUT)
+		cfg.p = old_cfg.p;
 
-	if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p)
+	if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p ||
+		old_cfg.sdm_data != cfg.sdm_data)
 		ret = _program_pll(hw, &cfg, rate);
 
 	if (pll->lock)
@@ -629,15 +771,15 @@
 	struct tegra_clk_pll *pll = to_clk_pll(hw);
 	struct tegra_clk_pll_freq_table cfg;
 
-	if (pll->params->flags & TEGRA_PLL_FIXED)
+	if (pll->params->flags & TEGRA_PLL_FIXED) {
+		/* PLLM/MB are used for memory; we do not change rate */
+		if (pll->params->flags & (TEGRA_PLLM | TEGRA_PLLMB))
+			return clk_hw_get_rate(hw);
 		return pll->params->fixed_rate;
-
-	/* PLLM is used for memory; we do not change rate */
-	if (pll->params->flags & TEGRA_PLLM)
-		return clk_hw_get_rate(hw);
+	}
 
 	if (_get_table_rate(hw, &cfg, rate, *prate) &&
-	    _calc_rate(hw, &cfg, rate, *prate))
+	    pll->params->calc_rate(hw, &cfg, rate, *prate))
 		return -EINVAL;
 
 	return cfg.output_rate;
@@ -658,6 +800,7 @@
 		return parent_rate;
 
 	if ((pll->params->flags & TEGRA_PLL_FIXED) &&
+	    !(pll->params->flags & (TEGRA_PLLM | TEGRA_PLLMB)) &&
 			!(val & PLL_BASE_OVERRIDE)) {
 		struct tegra_clk_pll_freq_table sel;
 		if (_get_table_rate(hw, &sel, pll->params->fixed_rate,
@@ -671,12 +814,20 @@
 
 	_get_pll_mnp(pll, &cfg);
 
-	pdiv = _hw_to_p_div(hw, cfg.p);
-	if (pdiv < 0) {
-		WARN_ON(1);
+	if (pll->params->flags & TEGRA_PLL_VCO_OUT) {
 		pdiv = 1;
+	} else {
+		pdiv = _hw_to_p_div(hw, cfg.p);
+		if (pdiv < 0) {
+			WARN(1, "Clock %s has invalid pdiv value : 0x%x\n",
+			     clk_hw_get_name(hw), cfg.p);
+			pdiv = 1;
+		}
 	}
 
+	if (pll->params->set_gain)
+		pll->params->set_gain(&cfg);
+
 	cfg.m *= pdiv;
 
 	rate *= cfg.n;
@@ -816,19 +967,65 @@
 	.enable = clk_plle_enable,
 };
 
-#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
-	defined(CONFIG_ARCH_TEGRA_124_SOC) || \
-	defined(CONFIG_ARCH_TEGRA_132_SOC)
-
 static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params,
 			   unsigned long parent_rate)
 {
+	u16 mdiv = parent_rate / pll_params->cf_min;
+
+	if (pll_params->flags & TEGRA_MDIV_NEW)
+		return (!pll_params->mdiv_default ? mdiv :
+			min(mdiv, pll_params->mdiv_default));
+
+	if (pll_params->mdiv_default)
+		return pll_params->mdiv_default;
+
 	if (parent_rate > pll_params->cf_max)
 		return 2;
 	else
 		return 1;
 }
 
+static int _calc_dynamic_ramp_rate(struct clk_hw *hw,
+				struct tegra_clk_pll_freq_table *cfg,
+				unsigned long rate, unsigned long parent_rate)
+{
+	struct tegra_clk_pll *pll = to_clk_pll(hw);
+	unsigned int p;
+	int p_div;
+
+	if (!rate)
+		return -EINVAL;
+
+	p = DIV_ROUND_UP(pll->params->vco_min, rate);
+	cfg->m = _pll_fixed_mdiv(pll->params, parent_rate);
+	cfg->output_rate = rate * p;
+	cfg->n = cfg->output_rate * cfg->m / parent_rate;
+	cfg->input_rate = parent_rate;
+
+	p_div = _p_div_to_hw(hw, p);
+	if (p_div < 0)
+		return p_div;
+
+	cfg->p = p_div;
+
+	if (cfg->n > divn_max(pll) || cfg->output_rate > pll->params->vco_max)
+		return -EINVAL;
+
+	return 0;
+}
+
+#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
+	defined(CONFIG_ARCH_TEGRA_124_SOC) || \
+	defined(CONFIG_ARCH_TEGRA_132_SOC) || \
+	defined(CONFIG_ARCH_TEGRA_210_SOC)
+
+u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate)
+{
+	struct tegra_clk_pll *pll = to_clk_pll(hw);
+
+	return (u16)_pll_fixed_mdiv(pll->params, input_rate);
+}
+
 static unsigned long _clip_vco_min(unsigned long vco_min,
 				   unsigned long parent_rate)
 {
@@ -871,86 +1068,12 @@
 	return 0;
 }
 
-static int clk_pll_iddq_enable(struct clk_hw *hw)
-{
-	struct tegra_clk_pll *pll = to_clk_pll(hw);
-	unsigned long flags = 0;
-
-	u32 val;
-	int ret;
-
-	if (pll->lock)
-		spin_lock_irqsave(pll->lock, flags);
-
-	val = pll_readl(pll->params->iddq_reg, pll);
-	val &= ~BIT(pll->params->iddq_bit_idx);
-	pll_writel(val, pll->params->iddq_reg, pll);
-	udelay(2);
-
-	_clk_pll_enable(hw);
-
-	ret = clk_pll_wait_for_lock(pll);
-
-	if (pll->lock)
-		spin_unlock_irqrestore(pll->lock, flags);
-
-	return 0;
-}
-
-static void clk_pll_iddq_disable(struct clk_hw *hw)
-{
-	struct tegra_clk_pll *pll = to_clk_pll(hw);
-	unsigned long flags = 0;
-	u32 val;
-
-	if (pll->lock)
-		spin_lock_irqsave(pll->lock, flags);
-
-	_clk_pll_disable(hw);
-
-	val = pll_readl(pll->params->iddq_reg, pll);
-	val |= BIT(pll->params->iddq_bit_idx);
-	pll_writel(val, pll->params->iddq_reg, pll);
-	udelay(2);
-
-	if (pll->lock)
-		spin_unlock_irqrestore(pll->lock, flags);
-}
-
-static int _calc_dynamic_ramp_rate(struct clk_hw *hw,
-				struct tegra_clk_pll_freq_table *cfg,
-				unsigned long rate, unsigned long parent_rate)
-{
-	struct tegra_clk_pll *pll = to_clk_pll(hw);
-	unsigned int p;
-	int p_div;
-
-	if (!rate)
-		return -EINVAL;
-
-	p = DIV_ROUND_UP(pll->params->vco_min, rate);
-	cfg->m = _pll_fixed_mdiv(pll->params, parent_rate);
-	cfg->output_rate = rate * p;
-	cfg->n = cfg->output_rate * cfg->m / parent_rate;
-
-	p_div = _p_div_to_hw(hw, p);
-	if (p_div < 0)
-		return p_div;
-	else
-		cfg->p = p_div;
-
-	if (cfg->n > divn_max(pll) || cfg->output_rate > pll->params->vco_max)
-		return -EINVAL;
-
-	return 0;
-}
-
 static int _pll_ramp_calc_pll(struct clk_hw *hw,
 			      struct tegra_clk_pll_freq_table *cfg,
 			      unsigned long rate, unsigned long parent_rate)
 {
 	struct tegra_clk_pll *pll = to_clk_pll(hw);
-	int err = 0, p_div;
+	int err = 0;
 
 	err = _get_table_rate(hw, cfg, rate, parent_rate);
 	if (err < 0)
@@ -961,11 +1084,6 @@
 			err = -EINVAL;
 			goto out;
 		}
-		p_div = _p_div_to_hw(hw, cfg->p);
-		if (p_div < 0)
-			return p_div;
-		else
-			cfg->p = p_div;
 	}
 
 	if (cfg->p >  pll->params->max_p)
@@ -991,6 +1109,8 @@
 		spin_lock_irqsave(pll->lock, flags);
 
 	_get_pll_mnp(pll, &old_cfg);
+	if (pll->params->flags & TEGRA_PLL_VCO_OUT)
+		cfg.p = old_cfg.p;
 
 	if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p)
 		ret = _program_pll(hw, &cfg, rate);
@@ -1004,6 +1124,7 @@
 static long clk_pll_ramp_round_rate(struct clk_hw *hw, unsigned long rate,
 				unsigned long *prate)
 {
+	struct tegra_clk_pll *pll = to_clk_pll(hw);
 	struct tegra_clk_pll_freq_table cfg;
 	int ret, p_div;
 	u64 output_rate = *prate;
@@ -1016,46 +1137,15 @@
 	if (p_div < 0)
 		return p_div;
 
+	if (pll->params->set_gain)
+		pll->params->set_gain(&cfg);
+
 	output_rate *= cfg.n;
 	do_div(output_rate, cfg.m * p_div);
 
 	return output_rate;
 }
 
-static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate,
-				unsigned long parent_rate)
-{
-	struct tegra_clk_pll_freq_table cfg;
-	struct tegra_clk_pll *pll = to_clk_pll(hw);
-	unsigned long flags = 0;
-	int state, ret = 0;
-
-	if (pll->lock)
-		spin_lock_irqsave(pll->lock, flags);
-
-	state = clk_pll_is_enabled(hw);
-	if (state) {
-		if (rate != clk_get_rate(hw->clk)) {
-			pr_err("%s: Cannot change active PLLM\n", __func__);
-			ret = -EINVAL;
-			goto out;
-		}
-		goto out;
-	}
-
-	ret = _pll_ramp_calc_pll(hw, &cfg, rate, parent_rate);
-	if (ret < 0)
-		goto out;
-
-	_update_pll_mnp(pll, &cfg);
-
-out:
-	if (pll->lock)
-		spin_unlock_irqrestore(pll->lock, flags);
-
-	return ret;
-}
-
 static void _pllcx_strobe(struct tegra_clk_pll *pll)
 {
 	u32 val;
@@ -1445,6 +1535,17 @@
 	init.parent_names = (parent_name ? &parent_name : NULL);
 	init.num_parents = (parent_name ? 1 : 0);
 
+	/* Default to _calc_rate if unspecified */
+	if (!pll->params->calc_rate) {
+		if (pll->params->flags & TEGRA_PLLM)
+			pll->params->calc_rate = _calc_dynamic_ramp_rate;
+		else
+			pll->params->calc_rate = _calc_rate;
+	}
+
+	if (pll->params->set_defaults)
+		pll->params->set_defaults(pll);
+
 	/* Data in .init is copied by clk_register(), so stack variable OK */
 	pll->hw.init = &init;
 
@@ -1460,7 +1561,7 @@
 	struct clk *clk;
 
 	pll_params->flags |= TEGRA_PLL_BYPASS;
-	pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+
 	pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
 	if (IS_ERR(pll))
 		return ERR_CAST(pll);
@@ -1490,8 +1591,7 @@
 	struct tegra_clk_pll *pll;
 	struct clk *clk;
 
-	pll_params->flags |= TEGRA_PLL_LOCK_MISC | TEGRA_PLL_BYPASS;
-	pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+	pll_params->flags |= TEGRA_PLL_BYPASS;
 
 	if (!pll_params->div_nmp)
 		pll_params->div_nmp = &pll_e_nmp;
@@ -1510,25 +1610,17 @@
 
 #if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
 	defined(CONFIG_ARCH_TEGRA_124_SOC) || \
-	defined(CONFIG_ARCH_TEGRA_132_SOC)
+	defined(CONFIG_ARCH_TEGRA_132_SOC) || \
+	defined(CONFIG_ARCH_TEGRA_210_SOC)
 static const struct clk_ops tegra_clk_pllxc_ops = {
 	.is_enabled = clk_pll_is_enabled,
-	.enable = clk_pll_iddq_enable,
-	.disable = clk_pll_iddq_disable,
+	.enable = clk_pll_enable,
+	.disable = clk_pll_disable,
 	.recalc_rate = clk_pll_recalc_rate,
 	.round_rate = clk_pll_ramp_round_rate,
 	.set_rate = clk_pllxc_set_rate,
 };
 
-static const struct clk_ops tegra_clk_pllm_ops = {
-	.is_enabled = clk_pll_is_enabled,
-	.enable = clk_pll_iddq_enable,
-	.disable = clk_pll_iddq_disable,
-	.recalc_rate = clk_pll_recalc_rate,
-	.round_rate = clk_pll_ramp_round_rate,
-	.set_rate = clk_pllm_set_rate,
-};
-
 static const struct clk_ops tegra_clk_pllc_ops = {
 	.is_enabled = clk_pll_is_enabled,
 	.enable = clk_pllc_enable,
@@ -1540,8 +1632,8 @@
 
 static const struct clk_ops tegra_clk_pllre_ops = {
 	.is_enabled = clk_pll_is_enabled,
-	.enable = clk_pll_iddq_enable,
-	.disable = clk_pll_iddq_disable,
+	.enable = clk_pll_enable,
+	.disable = clk_pll_disable,
 	.recalc_rate = clk_pllre_recalc_rate,
 	.round_rate = clk_pllre_round_rate,
 	.set_rate = clk_pllre_set_rate,
@@ -1564,7 +1656,6 @@
 	struct tegra_clk_pll *pll;
 	struct clk *clk, *parent;
 	unsigned long parent_rate;
-	int err;
 	u32 val, val_iddq;
 
 	parent = __clk_lookup(parent_name);
@@ -1581,21 +1672,33 @@
 
 	pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
 
-	err = _setup_dynamic_ramp(pll_params, clk_base, parent_rate);
-	if (err)
-		return ERR_PTR(err);
+	if (pll_params->adjust_vco)
+		pll_params->vco_min = pll_params->adjust_vco(pll_params,
+							     parent_rate);
 
-	val = readl_relaxed(clk_base + pll_params->base_reg);
-	val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg);
+	/*
+	 * If the pll has a set_defaults callback, it will take care of
+	 * configuring dynamic ramping and setting IDDQ in that path.
+	 */
+	if (!pll_params->set_defaults) {
+		int err;
 
-	if (val & PLL_BASE_ENABLE)
-		WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx));
-	else {
-		val_iddq |= BIT(pll_params->iddq_bit_idx);
-		writel_relaxed(val_iddq, clk_base + pll_params->iddq_reg);
+		err = _setup_dynamic_ramp(pll_params, clk_base, parent_rate);
+		if (err)
+			return ERR_PTR(err);
+
+		val = readl_relaxed(clk_base + pll_params->base_reg);
+		val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg);
+
+		if (val & PLL_BASE_ENABLE)
+			WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx));
+		else {
+			val_iddq |= BIT(pll_params->iddq_bit_idx);
+			writel_relaxed(val_iddq,
+				       clk_base + pll_params->iddq_reg);
+		}
 	}
 
-	pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
 	pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
 	if (IS_ERR(pll))
 		return ERR_CAST(pll);
@@ -1618,10 +1721,12 @@
 	struct tegra_clk_pll *pll;
 	struct clk *clk;
 
-	pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_LOCK_MISC;
-
 	pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
 
+	if (pll_params->adjust_vco)
+		pll_params->vco_min = pll_params->adjust_vco(pll_params,
+							     parent_rate);
+
 	pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
 	if (IS_ERR(pll))
 		return ERR_CAST(pll);
@@ -1630,7 +1735,8 @@
 
 	val = pll_readl_base(pll);
 	if (val & PLL_BASE_ENABLE)
-		WARN_ON(val & pll_params->iddq_bit_idx);
+		WARN_ON(readl_relaxed(clk_base + pll_params->iddq_reg) &
+				BIT(pll_params->iddq_bit_idx));
 	else {
 		int m;
 
@@ -1678,15 +1784,18 @@
 
 	pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
 
+	if (pll_params->adjust_vco)
+		pll_params->vco_min = pll_params->adjust_vco(pll_params,
+							     parent_rate);
+
 	pll_params->flags |= TEGRA_PLL_BYPASS;
-	pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
 	pll_params->flags |= TEGRA_PLLM;
 	pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
 	if (IS_ERR(pll))
 		return ERR_CAST(pll);
 
 	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
-				      &tegra_clk_pllm_ops);
+				      &tegra_clk_pll_ops);
 	if (IS_ERR(clk))
 		kfree(pll);
 
@@ -1700,7 +1809,7 @@
 			  spinlock_t *lock)
 {
 	struct clk *parent, *clk;
-	struct pdiv_map *p_tohw = pll_params->pdiv_tohw;
+	const struct pdiv_map *p_tohw = pll_params->pdiv_tohw;
 	struct tegra_clk_pll *pll;
 	struct tegra_clk_pll_freq_table cfg;
 	unsigned long parent_rate;
@@ -1777,7 +1886,6 @@
 	struct clk *clk;
 	u32 val, val_aux;
 
-	pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
 	pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
 	if (IS_ERR(pll))
 		return ERR_CAST(pll);
@@ -1810,8 +1918,8 @@
 #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
 static const struct clk_ops tegra_clk_pllss_ops = {
 	.is_enabled = clk_pll_is_enabled,
-	.enable = clk_pll_iddq_enable,
-	.disable = clk_pll_iddq_disable,
+	.enable = clk_pll_enable,
+	.disable = clk_pll_disable,
 	.recalc_rate = clk_pll_recalc_rate,
 	.round_rate = clk_pll_ramp_round_rate,
 	.set_rate = clk_pllxc_set_rate,
@@ -1826,7 +1934,7 @@
 	struct clk *clk, *parent;
 	struct tegra_clk_pll_freq_table cfg;
 	unsigned long parent_rate;
-	u32 val;
+	u32 val, val_iddq;
 	int i;
 
 	if (!pll_params->div_nmp)
@@ -1839,7 +1947,6 @@
 		return ERR_PTR(-EINVAL);
 	}
 
-	pll_params->flags = TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_USE_LOCK;
 	pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
 	if (IS_ERR(pll))
 		return ERR_CAST(pll);
@@ -1874,6 +1981,337 @@
 	pll_writel(PLLSS_CTRL1_DEFAULT, pll_params->ext_misc_reg[2], pll);
 
 	val = pll_readl_base(pll);
+	val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg);
+	if (val & PLL_BASE_ENABLE) {
+		if (val_iddq & BIT(pll_params->iddq_bit_idx)) {
+			WARN(1, "%s is on but IDDQ set\n", name);
+			kfree(pll);
+			return ERR_PTR(-EINVAL);
+		}
+	} else {
+		val_iddq |= BIT(pll_params->iddq_bit_idx);
+		writel_relaxed(val_iddq, clk_base + pll_params->iddq_reg);
+	}
+
+	val &= ~PLLSS_LOCK_OVERRIDE;
+	pll_writel_base(val, pll);
+
+	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+					&tegra_clk_pllss_ops);
+
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
+#endif
+
+#if defined(CONFIG_ARCH_TEGRA_210_SOC)
+static int clk_plle_tegra210_enable(struct clk_hw *hw)
+{
+	struct tegra_clk_pll *pll = to_clk_pll(hw);
+	struct tegra_clk_pll_freq_table sel;
+	u32 val;
+	int ret;
+	unsigned long flags = 0;
+	unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk));
+
+	if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate))
+		return -EINVAL;
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	val = pll_readl_base(pll);
+	val &= ~BIT(30); /* Disable lock override */
+	pll_writel_base(val, pll);
+
+	val = pll_readl(pll->params->aux_reg, pll);
+	val |= PLLE_AUX_ENABLE_SWCTL;
+	val &= ~PLLE_AUX_SEQ_ENABLE;
+	pll_writel(val, pll->params->aux_reg, pll);
+	udelay(1);
+
+	val = pll_readl_misc(pll);
+	val |= PLLE_MISC_LOCK_ENABLE;
+	val |= PLLE_MISC_IDDQ_SW_CTRL;
+	val &= ~PLLE_MISC_IDDQ_SW_VALUE;
+	val |= PLLE_MISC_PLLE_PTS;
+	val |= PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK;
+	pll_writel_misc(val, pll);
+	udelay(5);
+
+	val = pll_readl(PLLE_SS_CTRL, pll);
+	val |= PLLE_SS_DISABLE;
+	pll_writel(val, PLLE_SS_CTRL, pll);
+
+	val = pll_readl_base(pll);
+	val &= ~(divp_mask_shifted(pll) | divn_mask_shifted(pll) |
+		 divm_mask_shifted(pll));
+	val &= ~(PLLE_BASE_DIVCML_MASK << PLLE_BASE_DIVCML_SHIFT);
+	val |= sel.m << divm_shift(pll);
+	val |= sel.n << divn_shift(pll);
+	val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;
+	pll_writel_base(val, pll);
+	udelay(1);
+
+	val = pll_readl_base(pll);
+	val |= PLLE_BASE_ENABLE;
+	pll_writel_base(val, pll);
+
+	ret = clk_pll_wait_for_lock(pll);
+
+	if (ret < 0)
+		goto out;
+
+	val = pll_readl(PLLE_SS_CTRL, pll);
+	val &= ~(PLLE_SS_CNTL_CENTER | PLLE_SS_CNTL_INVERT);
+	val &= ~PLLE_SS_COEFFICIENTS_MASK;
+	val |= PLLE_SS_COEFFICIENTS_VAL;
+	pll_writel(val, PLLE_SS_CTRL, pll);
+	val &= ~(PLLE_SS_CNTL_SSC_BYP | PLLE_SS_CNTL_BYPASS_SS);
+	pll_writel(val, PLLE_SS_CTRL, pll);
+	udelay(1);
+	val &= ~PLLE_SS_CNTL_INTERP_RESET;
+	pll_writel(val, PLLE_SS_CTRL, pll);
+	udelay(1);
+
+	val = pll_readl_misc(pll);
+	val &= ~PLLE_MISC_IDDQ_SW_CTRL;
+	pll_writel_misc(val, pll);
+
+	val = pll_readl(pll->params->aux_reg, pll);
+	val |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SS_SEQ_INCLUDE);
+	val &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL);
+	pll_writel(val, pll->params->aux_reg, pll);
+	udelay(1);
+	val |= PLLE_AUX_SEQ_ENABLE;
+	pll_writel(val, pll->params->aux_reg, pll);
+
+out:
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+
+	return ret;
+}
+
+static void clk_plle_tegra210_disable(struct clk_hw *hw)
+{
+	struct tegra_clk_pll *pll = to_clk_pll(hw);
+	unsigned long flags = 0;
+	u32 val;
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	val = pll_readl_base(pll);
+	val &= ~PLLE_BASE_ENABLE;
+	pll_writel_base(val, pll);
+
+	val = pll_readl_misc(pll);
+	val |= PLLE_MISC_IDDQ_SW_CTRL | PLLE_MISC_IDDQ_SW_VALUE;
+	pll_writel_misc(val, pll);
+	udelay(1);
+
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static int clk_plle_tegra210_is_enabled(struct clk_hw *hw)
+{
+	struct tegra_clk_pll *pll = to_clk_pll(hw);
+	u32 val;
+
+	val = pll_readl_base(pll);
+
+	return val & PLLE_BASE_ENABLE ? 1 : 0;
+}
+
+static const struct clk_ops tegra_clk_plle_tegra210_ops = {
+	.is_enabled =  clk_plle_tegra210_is_enabled,
+	.enable = clk_plle_tegra210_enable,
+	.disable = clk_plle_tegra210_disable,
+	.recalc_rate = clk_pll_recalc_rate,
+};
+
+struct clk *tegra_clk_register_plle_tegra210(const char *name,
+				const char *parent_name,
+				void __iomem *clk_base, unsigned long flags,
+				struct tegra_clk_pll_params *pll_params,
+				spinlock_t *lock)
+{
+	struct tegra_clk_pll *pll;
+	struct clk *clk;
+	u32 val, val_aux;
+
+	pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
+	if (IS_ERR(pll))
+		return ERR_CAST(pll);
+
+	/* ensure parent is set to pll_re_vco */
+
+	val = pll_readl_base(pll);
+	val_aux = pll_readl(pll_params->aux_reg, pll);
+
+	if (val & PLLE_BASE_ENABLE) {
+		if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
+			(val_aux & PLLE_AUX_PLLP_SEL))
+			WARN(1, "pll_e enabled with unsupported parent %s\n",
+			  (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
+					"pll_re_vco");
+	} else {
+		val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
+		pll_writel(val_aux, pll_params->aux_reg, pll);
+	}
+
+	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+				      &tegra_clk_plle_tegra210_ops);
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
+
+struct clk *tegra_clk_register_pllc_tegra210(const char *name,
+			const char *parent_name, void __iomem *clk_base,
+			void __iomem *pmc, unsigned long flags,
+			struct tegra_clk_pll_params *pll_params,
+			spinlock_t *lock)
+{
+	struct clk *parent, *clk;
+	const struct pdiv_map *p_tohw = pll_params->pdiv_tohw;
+	struct tegra_clk_pll *pll;
+	unsigned long parent_rate;
+
+	if (!p_tohw)
+		return ERR_PTR(-EINVAL);
+
+	parent = __clk_lookup(parent_name);
+	if (!parent) {
+		WARN(1, "parent clk %s of %s must be registered first\n",
+			name, parent_name);
+		return ERR_PTR(-EINVAL);
+	}
+
+	parent_rate = clk_get_rate(parent);
+
+	pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
+
+	if (pll_params->adjust_vco)
+		pll_params->vco_min = pll_params->adjust_vco(pll_params,
+							     parent_rate);
+
+	pll_params->flags |= TEGRA_PLL_BYPASS;
+	pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
+	if (IS_ERR(pll))
+		return ERR_CAST(pll);
+
+	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+				      &tegra_clk_pll_ops);
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
+
+struct clk *tegra_clk_register_pllxc_tegra210(const char *name,
+			const char *parent_name, void __iomem *clk_base,
+			void __iomem *pmc, unsigned long flags,
+			struct tegra_clk_pll_params *pll_params,
+			spinlock_t *lock)
+{
+	struct tegra_clk_pll *pll;
+	struct clk *clk, *parent;
+	unsigned long parent_rate;
+
+	parent = __clk_lookup(parent_name);
+	if (!parent) {
+		WARN(1, "parent clk %s of %s must be registered first\n",
+			name, parent_name);
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (!pll_params->pdiv_tohw)
+		return ERR_PTR(-EINVAL);
+
+	parent_rate = clk_get_rate(parent);
+
+	pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
+
+	if (pll_params->adjust_vco)
+		pll_params->vco_min = pll_params->adjust_vco(pll_params,
+							     parent_rate);
+
+	pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
+	if (IS_ERR(pll))
+		return ERR_CAST(pll);
+
+	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+				      &tegra_clk_pll_ops);
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
+
+struct clk *tegra_clk_register_pllss_tegra210(const char *name,
+				const char *parent_name, void __iomem *clk_base,
+				unsigned long flags,
+				struct tegra_clk_pll_params *pll_params,
+				spinlock_t *lock)
+{
+	struct tegra_clk_pll *pll;
+	struct clk *clk, *parent;
+	struct tegra_clk_pll_freq_table cfg;
+	unsigned long parent_rate;
+	u32 val;
+	int i;
+
+	if (!pll_params->div_nmp)
+		return ERR_PTR(-EINVAL);
+
+	parent = __clk_lookup(parent_name);
+	if (!parent) {
+		WARN(1, "parent clk %s of %s must be registered first\n",
+			name, parent_name);
+		return ERR_PTR(-EINVAL);
+	}
+
+	pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
+	if (IS_ERR(pll))
+		return ERR_CAST(pll);
+
+	val = pll_readl_base(pll);
+	val &= ~PLLSS_REF_SRC_SEL_MASK;
+	pll_writel_base(val, pll);
+
+	parent_rate = clk_get_rate(parent);
+
+	pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
+
+	if (pll_params->adjust_vco)
+		pll_params->vco_min = pll_params->adjust_vco(pll_params,
+							     parent_rate);
+
+	/* initialize PLL to minimum rate */
+
+	cfg.m = _pll_fixed_mdiv(pll_params, parent_rate);
+	cfg.n = cfg.m * pll_params->vco_min / parent_rate;
+
+	for (i = 0; pll_params->pdiv_tohw[i].pdiv; i++)
+		;
+	if (!i) {
+		kfree(pll);
+		return ERR_PTR(-EINVAL);
+	}
+
+	cfg.p = pll_params->pdiv_tohw[i-1].hw_val;
+
+	_update_pll_mnp(pll, &cfg);
+
+	pll_writel_misc(PLLSS_MISC_DEFAULT, pll);
+
+	val = pll_readl_base(pll);
 	if (val & PLL_BASE_ENABLE) {
 		if (val & BIT(pll_params->iddq_bit_idx)) {
 			WARN(1, "%s is on but IDDQ set\n", name);
@@ -1887,11 +2325,53 @@
 	pll_writel_base(val, pll);
 
 	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
-					&tegra_clk_pllss_ops);
+					&tegra_clk_pll_ops);
 
 	if (IS_ERR(clk))
 		kfree(pll);
 
 	return clk;
 }
+
+struct clk *tegra_clk_register_pllmb(const char *name, const char *parent_name,
+			  void __iomem *clk_base, void __iomem *pmc,
+			  unsigned long flags,
+			  struct tegra_clk_pll_params *pll_params,
+			  spinlock_t *lock)
+{
+	struct tegra_clk_pll *pll;
+	struct clk *clk, *parent;
+	unsigned long parent_rate;
+
+	if (!pll_params->pdiv_tohw)
+		return ERR_PTR(-EINVAL);
+
+	parent = __clk_lookup(parent_name);
+	if (!parent) {
+		WARN(1, "parent clk %s of %s must be registered first\n",
+			parent_name, name);
+		return ERR_PTR(-EINVAL);
+	}
+
+	parent_rate = clk_get_rate(parent);
+
+	pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate);
+
+	if (pll_params->adjust_vco)
+		pll_params->vco_min = pll_params->adjust_vco(pll_params,
+							     parent_rate);
+
+	pll_params->flags |= TEGRA_PLL_BYPASS;
+	pll_params->flags |= TEGRA_PLLMB;
+	pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
+	if (IS_ERR(pll))
+		return ERR_CAST(pll);
+
+	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+				      &tegra_clk_pll_ops);
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
 #endif
diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c
index cb6ab83..6ad381a 100644
--- a/drivers/clk/tegra/clk-tegra-periph.c
+++ b/drivers/clk/tegra/clk-tegra-periph.c
@@ -124,6 +124,20 @@
 #define CLK_SOURCE_HDMI_AUDIO 0x668
 #define CLK_SOURCE_VIC03 0x678
 #define CLK_SOURCE_CLK72MHZ 0x66c
+#define CLK_SOURCE_DBGAPB 0x718
+#define CLK_SOURCE_NVENC 0x6a0
+#define CLK_SOURCE_NVDEC 0x698
+#define CLK_SOURCE_NVJPG 0x69c
+#define CLK_SOURCE_APE 0x6c0
+#define CLK_SOURCE_SOR1 0x410
+#define CLK_SOURCE_SDMMC_LEGACY 0x694
+#define CLK_SOURCE_QSPI 0x6c4
+#define CLK_SOURCE_VI_I2C 0x6c8
+#define CLK_SOURCE_MIPIBIF 0x660
+#define CLK_SOURCE_UARTAPE 0x710
+#define CLK_SOURCE_TSECB 0x6d8
+#define CLK_SOURCE_MAUD 0x6d4
+#define CLK_SOURCE_USB2_HSIC_TRK 0x6cc
 
 #define MASK(x) (BIT(x) - 1)
 
@@ -182,6 +196,13 @@
 			TEGRA_DIVIDER_ROUND_UP, _clk_num, 0, _clk_id,\
 			_parents##_idx, 0, NULL)
 
+#define UART8(_name, _parents, _offset,\
+			     _clk_num, _clk_id)			\
+	TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\
+			29, MASK(3), 0, 0, 16, 1, TEGRA_DIVIDER_UART| \
+			TEGRA_DIVIDER_ROUND_UP, _clk_num, 0, _clk_id,\
+			_parents##_idx, 0, NULL)
+
 #define I2C(_name, _parents, _offset,\
 			     _clk_num, _clk_id)			\
 	TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\
@@ -221,8 +242,21 @@
 		.flags = _flags						\
 	}
 
+#define DIV8(_name, _parent_name, _offset, _clk_id, _flags)		\
+	{								\
+		.name = _name,						\
+		.clk_id = _clk_id,					\
+		.p.parent_name = _parent_name,				\
+		.periph = TEGRA_CLK_PERIPH(0, 0, 0, 0, 8, 1,		\
+				TEGRA_DIVIDER_ROUND_UP, 0, 0,		\
+				NULL, NULL),				\
+		.offset = _offset,					\
+		.flags = _flags,					\
+	}
+
 #define PLLP_BASE 0xa0
 #define PLLP_MISC 0xac
+#define PLLP_MISC1 0x680
 #define PLLP_OUTA 0xa4
 #define PLLP_OUTB 0xa8
 #define PLLP_OUTC 0x67c
@@ -234,6 +268,7 @@
 static DEFINE_SPINLOCK(PLLP_OUTB_lock);
 static DEFINE_SPINLOCK(PLLP_OUTC_lock);
 static DEFINE_SPINLOCK(sor0_lock);
+static DEFINE_SPINLOCK(sor1_lock);
 
 #define MUX_I2S_SPDIF(_id)						\
 static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = { "pll_a_out0", \
@@ -285,6 +320,68 @@
 	[0] = 0, [1] = 3,
 };
 
+static const char *mux_pllp_clkm_2[] = {
+	"pll_p", "clk_m"
+};
+static u32 mux_pllp_clkm_2_idx[] = {
+	[0] = 2, [1] = 6,
+};
+
+static const char *mux_pllc2_c_c3_pllp_plla1_clkm[] = {
+	"pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a1", "clk_m"
+};
+static u32 mux_pllc2_c_c3_pllp_plla1_clkm_idx[] = {
+	[0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 6, [5] = 7,
+};
+
+static const char *
+mux_pllc4_out1_pllc_pllc4_out2_pllp_clkm_plla_pllc4_out0[] = {
+	"pll_c4_out1", "pll_c", "pll_c4_out2", "pll_p", "clk_m",
+	"pll_a_out0", "pll_c4_out0"
+};
+static u32 mux_pllc4_out1_pllc_pllc4_out2_pllp_clkm_plla_pllc4_out0_idx[] = {
+	[0] = 0, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6, [6] = 7,
+};
+
+static const char *mux_pllc_pllp_plla[] = {
+	"pll_c", "pll_p", "pll_a_out0"
+};
+static u32 mux_pllc_pllp_plla_idx[] = {
+	[0] = 1, [1] = 2, [2] = 3,
+};
+
+static const char *mux_clkm_pllc_pllp_plla[] = {
+	"clk_m", "pll_c", "pll_p", "pll_a_out0"
+};
+#define mux_clkm_pllc_pllp_plla_idx NULL
+
+static const char *mux_pllc_pllp_plla1_pllc2_c3_clkm[] = {
+	"pll_c", "pll_p", "pll_a1", "pll_c2", "pll_c3", "clk_m"
+};
+static u32 mux_pllc_pllp_plla1_pllc2_c3_clkm_idx[] = {
+	[0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6,
+};
+
+static const char *mux_pllc2_c_c3_pllp_clkm_plla1_pllc4[] = {
+	"pll_c2", "pll_c", "pll_c3", "pll_p", "clk_m", "pll_a1", "pll_c4_out0",
+};
+static u32 mux_pllc2_c_c3_pllp_clkm_plla1_pllc4_idx[] = {
+	[0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6, [6] = 7,
+};
+
+static const char *mux_pllc_pllp_plla1_pllc2_c3_clkm_pllc4[] = {
+	"pll_c", "pll_p", "pll_a1", "pll_c2", "pll_c3", "clk_m", "pll_c4_out0",
+};
+#define mux_pllc_pllp_plla1_pllc2_c3_clkm_pllc4_idx \
+	mux_pllc2_c_c3_pllp_clkm_plla1_pllc4_idx
+
+static const char *
+mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm[] = {
+	"pll_a_out0", "pll_c4_out0", "pll_c", "pll_c4_out1", "pll_p",
+	"pll_c4_out2", "clk_m"
+};
+#define mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm_idx NULL
+
 static const char *mux_pllm_pllc2_c_c3_pllp_plla[] = {
 	"pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0"
 };
@@ -302,12 +399,93 @@
 #define mux_pllm_pllc_pllp_plla_idx mux_pllp_pllc_pllm_clkm_idx
 
 static const char *mux_pllp_pllc_clkm[] = {
-	"pll_p", "pll_c", "pll_m"
+	"pll_p", "pll_c", "clk_m"
 };
 static u32 mux_pllp_pllc_clkm_idx[] = {
 	[0] = 0, [1] = 1, [2] = 3,
 };
 
+static const char *mux_pllp_pllc_clkm_1[] = {
+	"pll_p", "pll_c", "clk_m"
+};
+static u32 mux_pllp_pllc_clkm_1_idx[] = {
+	[0] = 0, [1] = 2, [2] = 5,
+};
+
+static const char *mux_pllp_pllc_plla_clkm[] = {
+	"pll_p", "pll_c", "pll_a_out0", "clk_m"
+};
+static u32 mux_pllp_pllc_plla_clkm_idx[] = {
+	[0] = 0, [1] = 2, [2] = 4, [3] = 6,
+};
+
+static const char *mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2[] = {
+	"pll_p", "pll_c", "pll_c4_out0", "pll_c4_out1", "clk_m", "pll_c4_out2"
+};
+static u32 mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2_idx[] = {
+	[0] = 0, [1] = 2, [2] = 3, [3] = 5, [4] = 6, [5] = 7,
+};
+
+static const char *
+mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0[] = {
+	"pll_p", "pll_c_out1", "pll_c", "pll_c4_out2", "pll_c4_out1",
+	"clk_m", "pll_c4_out0"
+};
+static u32
+mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0_idx[] = {
+	[0] = 0, [1] = 1, [2] = 2, [3] = 4, [4] = 5, [5] = 6, [6] = 7,
+};
+
+static const char *mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0[] = {
+	"pll_p", "pll_c4_out2", "pll_c4_out1", "clk_m", "pll_c4_out0"
+};
+static u32 mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0_idx[] = {
+	[0] = 0, [1] = 3, [2] = 4, [3] = 6, [4] = 7,
+};
+
+static const char *mux_pllp_clkm_pllc4_out2_out1_out0_lj[] = {
+	"pll_p",
+	"pll_c4_out2", "pll_c4_out0",	/* LJ input */
+	"pll_c4_out2", "pll_c4_out1",
+	"pll_c4_out1",			/* LJ input */
+	"clk_m", "pll_c4_out0"
+};
+#define mux_pllp_clkm_pllc4_out2_out1_out0_lj_idx NULL
+
+static const char *mux_pllp_pllc2_c_c3_clkm[] = {
+	"pll_p", "pll_c2", "pll_c", "pll_c3", "clk_m"
+};
+static u32 mux_pllp_pllc2_c_c3_clkm_idx[] = {
+	[0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 6,
+};
+
+static const char *mux_pllp_clkm_clk32_plle[] = {
+	"pll_p", "clk_m", "clk_32k", "pll_e"
+};
+static u32 mux_pllp_clkm_clk32_plle_idx[] = {
+	[0] = 0, [1] = 2, [2] = 4, [3] = 6,
+};
+
+static const char *mux_pllp_pllp_out3_clkm_clk32k_plla[] = {
+	"pll_p", "pll_p_out3", "clk_m", "clk_32k", "pll_a_out0"
+};
+#define mux_pllp_pllp_out3_clkm_clk32k_plla_idx NULL
+
+static const char *mux_pllp_out3_clkm_pllp_pllc4[] = {
+	"pll_p_out3", "clk_m", "pll_p", "pll_c4_out0", "pll_c4_out1",
+	"pll_c4_out2"
+};
+static u32 mux_pllp_out3_clkm_pllp_pllc4_idx[] = {
+	[0] = 0, [1] = 3, [2] = 4, [3] = 5, [4] = 6, [5] = 7,
+};
+
+static const char *mux_clkm_pllp_pllre[] = {
+	"clk_m", "pll_p_out_xusb", "pll_re_out"
+};
+static u32 mux_clkm_pllp_pllre_idx[] = {
+	[0] = 0, [1] = 1, [2] = 5,
+};
+
 static const char *mux_pllp_pllc_clkm_clk32[] = {
 	"pll_p", "pll_c", "clk_m", "clk_32k"
 };
@@ -332,6 +510,11 @@
 	[0] = 0, [1] = 2, [2] = 4, [3] = 6,
 };
 
+static const char *mux_clkm_pllre_clk32_480M[] = {
+	"clk_m", "pll_re_out", "clk_32k", "pll_u_480M"
+};
+#define mux_clkm_pllre_clk32_480M_idx NULL
+
 static const char *mux_clkm_pllre_clk32_480M_pllc_ref[] = {
 	"clk_m", "pll_re_out", "clk_32k", "pll_u_480M", "pll_c", "pll_ref"
 };
@@ -339,10 +522,27 @@
 	[0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 4, [5] = 7,
 };
 
-static const char *mux_ss_60M[] = {
+static const char *mux_pllp_out3_pllp_pllc_clkm[] = {
+	"pll_p_out3", "pll_p", "pll_c", "clk_m"
+};
+static u32 mux_pllp_out3_pllp_pllc_clkm_idx[] = {
+	[0] = 0, [1] = 1, [2] = 2, [3] = 6,
+};
+
+static const char *mux_ss_div2_60M[] = {
 	"xusb_ss_div2", "pll_u_60M"
 };
-#define mux_ss_60M_idx NULL
+#define mux_ss_div2_60M_idx NULL
+
+static const char *mux_ss_div2_60M_ss[] = {
+	"xusb_ss_div2", "pll_u_60M", "xusb_ss_src"
+};
+#define mux_ss_div2_60M_ss_idx NULL
+
+static const char *mux_ss_clkm[] = {
+	"xusb_ss_src", "clk_m"
+};
+#define mux_ss_clkm_idx NULL
 
 static const char *mux_d_audio_clk[] = {
 	"pll_a_out0", "pll_p", "clk_m", "spdif_in_sync", "i2s0_sync",
@@ -386,6 +586,32 @@
 	[0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6, [6] = 7,
 };
 
+/* SOR1 mux'es */
+static const char *mux_pllp_plld_plld2_clkm[] = {
+	"pll_p", "pll_d_out0", "pll_d2_out0", "clk_m"
+};
+static u32 mux_pllp_plld_plld2_clkm_idx[] = {
+	[0] = 0, [1] = 2, [2] = 5, [3] = 6
+};
+
+static const char *mux_plldp_sor1_src[] = {
+	"pll_dp", "clk_sor1_src"
+};
+#define mux_plldp_sor1_src_idx NULL
+
+static const char *mux_clkm_sor1_brick_sor1_src[] = {
+	"clk_m", "sor1_brick", "sor1_src", "sor1_brick"
+};
+#define mux_clkm_sor1_brick_sor1_src_idx NULL
+
+static const char *mux_pllp_pllre_clkm[] = {
+	"pll_p", "pll_re_out1", "clk_m"
+};
+
+static u32 mux_pllp_pllre_clkm_idx[] = {
+	[0] = 0, [1] = 2, [2] = 3,
+};
+
 static const char *mux_clkm_plldp_sor0lvds[] = {
 	"clk_m", "pll_dp", "sor0_lvds",
 };
@@ -401,6 +627,7 @@
 	I2C("i2c3", mux_pllp_clkm, CLK_SOURCE_I2C3, 67, tegra_clk_i2c3),
 	I2C("i2c4", mux_pllp_clkm, CLK_SOURCE_I2C4, 103, tegra_clk_i2c4),
 	I2C("i2c5", mux_pllp_clkm, CLK_SOURCE_I2C5, 47, tegra_clk_i2c5),
+	I2C("i2c6", mux_pllp_clkm, CLK_SOURCE_I2C6, 166, tegra_clk_i2c6),
 	INT("vde", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VDE, 61, 0, tegra_clk_vde),
 	INT("vi", mux_pllm_pllc_pllp_plla, CLK_SOURCE_VI, 20, 0, tegra_clk_vi),
 	INT("epp", mux_pllm_pllc_pllp_plla, CLK_SOURCE_EPP, 19, 0, tegra_clk_epp),
@@ -411,14 +638,19 @@
 	INT8("vde", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_VDE, 61, 0, tegra_clk_vde_8),
 	INT8("vi", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI, 20, 0, tegra_clk_vi_8),
 	INT8("vi", mux_pllm_pllc2_c_c3_pllp_plla_pllc4, CLK_SOURCE_VI, 20, 0, tegra_clk_vi_9),
+	INT8("vi", mux_pllc2_c_c3_pllp_clkm_plla1_pllc4, CLK_SOURCE_VI, 20, 0, tegra_clk_vi_10),
 	INT8("epp", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_EPP, 19, 0, tegra_clk_epp_8),
 	INT8("msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, TEGRA_PERIPH_WAR_1005168, tegra_clk_msenc),
 	INT8("tsec", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_TSEC, 83, 0, tegra_clk_tsec),
+	INT("tsec", mux_pllp_pllc_clkm, CLK_SOURCE_TSEC, 83, 0, tegra_clk_tsec_8),
 	INT8("host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x_8),
+	INT8("host1x", mux_pllc4_out1_pllc_pllc4_out2_pllp_clkm_plla_pllc4_out0, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x_9),
 	INT8("se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se),
+	INT8("se", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se),
 	INT8("2d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_2D, 21, 0, tegra_clk_gr2d_8),
 	INT8("3d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_3D, 24, 0, tegra_clk_gr3d_8),
 	INT8("vic03", mux_pllm_pllc_pllp_plla_pllc2_c3_clkm, CLK_SOURCE_VIC03, 178, 0, tegra_clk_vic03),
+	INT8("vic03", mux_pllc_pllp_plla1_pllc2_c3_clkm, CLK_SOURCE_VIC03, 178, 0, tegra_clk_vic03_8),
 	INT_FLAGS("mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, 0, tegra_clk_mselect, CLK_IGNORE_UNUSED),
 	MUX("i2s0", mux_pllaout0_audio0_2x_pllp_clkm, CLK_SOURCE_I2S0, 30, TEGRA_PERIPH_ON_APB, tegra_clk_i2s0),
 	MUX("i2s1", mux_pllaout0_audio1_2x_pllp_clkm, CLK_SOURCE_I2S1, 11, TEGRA_PERIPH_ON_APB, tegra_clk_i2s1),
@@ -427,22 +659,31 @@
 	MUX("i2s4", mux_pllaout0_audio4_2x_pllp_clkm, CLK_SOURCE_I2S4, 102, TEGRA_PERIPH_ON_APB, tegra_clk_i2s4),
 	MUX("spdif_out", mux_pllaout0_audio_2x_pllp_clkm, CLK_SOURCE_SPDIF_OUT, 10, TEGRA_PERIPH_ON_APB, tegra_clk_spdif_out),
 	MUX("spdif_in", mux_pllp_pllc_pllm, CLK_SOURCE_SPDIF_IN, 10, TEGRA_PERIPH_ON_APB, tegra_clk_spdif_in),
+	MUX8("spdif_in", mux_pllp_pllc_clkm_1, CLK_SOURCE_SPDIF_IN, 10, TEGRA_PERIPH_ON_APB, tegra_clk_spdif_in_8),
 	MUX("pwm", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_PWM, 17, TEGRA_PERIPH_ON_APB, tegra_clk_pwm),
 	MUX("adx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX, 154, TEGRA_PERIPH_ON_APB, tegra_clk_adx),
 	MUX("amx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX, 153, TEGRA_PERIPH_ON_APB, tegra_clk_amx),
 	MUX("hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA, 125, TEGRA_PERIPH_ON_APB, tegra_clk_hda),
+	MUX("hda", mux_pllp_pllc_clkm, CLK_SOURCE_HDA, 125, TEGRA_PERIPH_ON_APB, tegra_clk_hda_8),
 	MUX("hda2codec_2x", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, TEGRA_PERIPH_ON_APB, tegra_clk_hda2codec_2x),
+	MUX8("hda2codec_2x", mux_pllp_pllc_plla_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, TEGRA_PERIPH_ON_APB, tegra_clk_hda2codec_2x_8),
 	MUX("vfir", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VFIR, 7, TEGRA_PERIPH_ON_APB, tegra_clk_vfir),
 	MUX("sdmmc1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1),
 	MUX("sdmmc2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2),
 	MUX("sdmmc3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3),
 	MUX("sdmmc4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4),
+	MUX8("sdmmc1", mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1_9),
+	MUX8("sdmmc2", mux_pllp_clkm_pllc4_out2_out1_out0_lj, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2_9),
+	MUX8("sdmmc3", mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3_9),
+	MUX8("sdmmc4", mux_pllp_clkm_pllc4_out2_out1_out0_lj, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4_9),
 	MUX("la", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_LA, 76, TEGRA_PERIPH_ON_APB, tegra_clk_la),
 	MUX("trace", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_TRACE, 77, TEGRA_PERIPH_ON_APB, tegra_clk_trace),
 	MUX("owr", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_OWR, 71, TEGRA_PERIPH_ON_APB, tegra_clk_owr),
+	MUX("owr", mux_pllp_pllc_clkm, CLK_SOURCE_OWR, 71, TEGRA_PERIPH_ON_APB, tegra_clk_owr_8),
 	MUX("nor", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NOR, 42, 0, tegra_clk_nor),
 	MUX("mipi", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_MIPI, 50, TEGRA_PERIPH_ON_APB, tegra_clk_mipi),
 	MUX("vi_sensor", mux_pllm_pllc_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor),
+	MUX("vi_sensor", mux_pllc_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor_9),
 	MUX("cilab", mux_pllp_pllc_clkm, CLK_SOURCE_CILAB, 144, 0, tegra_clk_cilab),
 	MUX("cilcd", mux_pllp_pllc_clkm, CLK_SOURCE_CILCD, 145, 0, tegra_clk_cilcd),
 	MUX("cile", mux_pllp_pllc_clkm, CLK_SOURCE_CILE, 146, 0, tegra_clk_cile),
@@ -465,10 +706,13 @@
 	MUX("ndflash", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NDFLASH, 13, TEGRA_PERIPH_ON_APB, tegra_clk_ndflash),
 	MUX("ndspeed", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NDSPEED, 80, TEGRA_PERIPH_ON_APB, tegra_clk_ndspeed),
 	MUX("sata_oob", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SATA_OOB, 123, TEGRA_PERIPH_ON_APB, tegra_clk_sata_oob),
+	MUX("sata_oob", mux_pllp_pllc_clkm, CLK_SOURCE_SATA_OOB, 123, TEGRA_PERIPH_ON_APB, tegra_clk_sata_oob_8),
 	MUX("sata", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SATA, 124, TEGRA_PERIPH_ON_APB, tegra_clk_sata),
+	MUX("sata", mux_pllp_pllc_clkm, CLK_SOURCE_SATA, 124, TEGRA_PERIPH_ON_APB, tegra_clk_sata_8),
 	MUX("adx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX1, 180, TEGRA_PERIPH_ON_APB, tegra_clk_adx1),
 	MUX("amx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX1, 185, TEGRA_PERIPH_ON_APB, tegra_clk_amx1),
 	MUX("vi_sensor2", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR2, 165, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2),
+	MUX("vi_sensor2", mux_pllc_pllp_plla, CLK_SOURCE_VI_SENSOR2, 165, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2_8),
 	MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1_8),
 	MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2_8),
 	MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3_8),
@@ -479,6 +723,10 @@
 	MUX8("sbc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC4, 68, TEGRA_PERIPH_ON_APB, tegra_clk_sbc4_8),
 	MUX8("sbc5", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC5, 104, TEGRA_PERIPH_ON_APB, tegra_clk_sbc5_8),
 	MUX8("sbc6", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC6, 105, TEGRA_PERIPH_ON_APB, tegra_clk_sbc6_8),
+	MUX("sbc1", mux_pllp_pllc_clkm, CLK_SOURCE_SBC1, 41, TEGRA_PERIPH_ON_APB, tegra_clk_sbc1_9),
+	MUX("sbc2", mux_pllp_pllc_clkm, CLK_SOURCE_SBC2, 44, TEGRA_PERIPH_ON_APB, tegra_clk_sbc2_9),
+	MUX("sbc3", mux_pllp_pllc_clkm, CLK_SOURCE_SBC3, 46, TEGRA_PERIPH_ON_APB, tegra_clk_sbc3_9),
+	MUX("sbc4", mux_pllp_pllc_clkm, CLK_SOURCE_SBC4, 68, TEGRA_PERIPH_ON_APB, tegra_clk_sbc4_9),
 	MUX8("ndflash", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDFLASH, 13, TEGRA_PERIPH_ON_APB, tegra_clk_ndflash_8),
 	MUX8("ndspeed", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDSPEED, 80, TEGRA_PERIPH_ON_APB, tegra_clk_ndspeed_8),
 	MUX8("hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, 0, tegra_clk_hdmi),
@@ -486,27 +734,59 @@
 	MUX8("extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, 0, tegra_clk_extern2),
 	MUX8("extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, 0, tegra_clk_extern3),
 	MUX8("soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm),
+	MUX8("soc_therm", mux_clkm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm_8),
 	MUX8("vi_sensor", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 164, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor_8),
 	MUX8("isp", mux_pllm_pllc_pllp_plla_clkm_pllc4, CLK_SOURCE_ISP, 23, TEGRA_PERIPH_ON_APB, tegra_clk_isp_8),
+	MUX8("isp", mux_pllc_pllp_plla1_pllc2_c3_clkm_pllc4, CLK_SOURCE_ISP, 23, TEGRA_PERIPH_ON_APB, tegra_clk_isp_9),
 	MUX8("entropy", mux_pllp_clkm1, CLK_SOURCE_ENTROPY, 149,  0, tegra_clk_entropy),
+	MUX8("entropy", mux_pllp_clkm_clk32_plle, CLK_SOURCE_ENTROPY, 149,  0, tegra_clk_entropy_8),
 	MUX8("hdmi_audio", mux_pllp3_pllc_clkm, CLK_SOURCE_HDMI_AUDIO, 176, TEGRA_PERIPH_NO_RESET, tegra_clk_hdmi_audio),
 	MUX8("clk72mhz", mux_pllp3_pllc_clkm, CLK_SOURCE_CLK72MHZ, 177, TEGRA_PERIPH_NO_RESET, tegra_clk_clk72Mhz),
+	MUX8("clk72mhz", mux_pllp_out3_pllp_pllc_clkm, CLK_SOURCE_CLK72MHZ, 177, TEGRA_PERIPH_NO_RESET, tegra_clk_clk72Mhz_8),
 	MUX8_NOGATE_LOCK("sor0_lvds", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_SOR0, tegra_clk_sor0_lvds, &sor0_lock),
 	MUX_FLAGS("csite", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_CSITE, 73, TEGRA_PERIPH_ON_APB, tegra_clk_csite, CLK_IGNORE_UNUSED),
+	MUX_FLAGS("csite", mux_pllp_pllre_clkm, CLK_SOURCE_CSITE, 73, TEGRA_PERIPH_ON_APB, tegra_clk_csite_8, CLK_IGNORE_UNUSED),
 	NODIV("disp1", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP1, 29, 7, 27, 0, tegra_clk_disp1, NULL),
+	NODIV("disp1", mux_pllp_plld_plld2_clkm, CLK_SOURCE_DISP1, 29, 7, 27, 0, tegra_clk_disp1_8, NULL),
 	NODIV("disp2", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP2, 29, 7, 26, 0, tegra_clk_disp2, NULL),
+	NODIV("disp2", mux_pllp_plld_plld2_clkm, CLK_SOURCE_DISP2, 29, 7, 26, 0, tegra_clk_disp2_8, NULL),
 	NODIV("sor0", mux_clkm_plldp_sor0lvds, CLK_SOURCE_SOR0, 14, 3, 182, 0, tegra_clk_sor0, &sor0_lock),
 	UART("uarta", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTA, 6, tegra_clk_uarta),
 	UART("uartb", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTB, 7, tegra_clk_uartb),
 	UART("uartc", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTC, 55, tegra_clk_uartc),
 	UART("uartd", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTD, 65, tegra_clk_uartd),
 	UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 66, tegra_clk_uarte),
+	UART8("uarta", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTA, 6, tegra_clk_uarta_8),
+	UART8("uartb", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTB, 7, tegra_clk_uartb_8),
+	UART8("uartc", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTC, 55, tegra_clk_uartc_8),
+	UART8("uartd", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTD, 65, tegra_clk_uartd_8),
 	XUSB("xusb_host_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_host_src),
+	XUSB("xusb_host_src", mux_clkm_pllp_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_host_src_8),
 	XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src),
+	XUSB("xusb_falcon_src", mux_clkm_pllp_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src_8),
 	XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src),
 	XUSB("xusb_ss_src", mux_clkm_pllre_clk32_480M_pllc_ref, CLK_SOURCE_XUSB_SS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ss_src),
-	NODIV("xusb_hs_src", mux_ss_60M, CLK_SOURCE_XUSB_SS_SRC, 25, MASK(1), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_hs_src, NULL),
+	XUSB("xusb_ss_src", mux_clkm_pllre_clk32_480M, CLK_SOURCE_XUSB_SS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ss_src_8),
+	NODIV("xusb_hs_src", mux_ss_div2_60M, CLK_SOURCE_XUSB_SS_SRC, 25, MASK(1), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_hs_src, NULL),
+	NODIV("xusb_hs_src", mux_ss_div2_60M_ss, CLK_SOURCE_XUSB_SS_SRC, 25, MASK(2), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_hs_src_4, NULL),
+	NODIV("xusb_ssp_src", mux_ss_clkm, CLK_SOURCE_XUSB_SS_SRC, 24, MASK(1), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ssp_src, NULL),
 	XUSB("xusb_dev_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src),
+	XUSB("xusb_dev_src", mux_clkm_pllp_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src_8),
+	MUX8("dbgapb", mux_pllp_clkm_2, CLK_SOURCE_DBGAPB, 185, TEGRA_PERIPH_NO_RESET, tegra_clk_dbgapb),
+	MUX8("msenc", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVENC, 219, 0, tegra_clk_nvenc),
+	MUX8("nvdec", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVDEC, 194, 0, tegra_clk_nvdec),
+	MUX8("nvjpg", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVJPG, 195, 0, tegra_clk_nvjpg),
+	MUX8("ape", mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm, CLK_SOURCE_APE, 198, TEGRA_PERIPH_ON_APB, tegra_clk_ape),
+	MUX8_NOGATE_LOCK("sor1_src", mux_pllp_plld_plld2_clkm, CLK_SOURCE_SOR1, tegra_clk_sor1_src, &sor1_lock),
+	NODIV("sor1_brick", mux_plldp_sor1_src, CLK_SOURCE_SOR1, 14, MASK(1), 183, 0, tegra_clk_sor1_brick, &sor1_lock),
+	NODIV("sor1", mux_clkm_sor1_brick_sor1_src, CLK_SOURCE_SOR1, 15, MASK(1), 183, 0, tegra_clk_sor1, &sor1_lock),
+	MUX8("sdmmc_legacy", mux_pllp_out3_clkm_pllp_pllc4, CLK_SOURCE_SDMMC_LEGACY, 193, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_sdmmc_legacy),
+	MUX8("qspi", mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_QSPI, 211, TEGRA_PERIPH_ON_APB, tegra_clk_qspi),
+	MUX("vii2c", mux_pllp_pllc_clkm, CLK_SOURCE_VI_I2C, 208, TEGRA_PERIPH_ON_APB, tegra_clk_vi_i2c),
+	MUX("mipibif", mux_pllp_clkm, CLK_SOURCE_MIPIBIF, 173, TEGRA_PERIPH_ON_APB, tegra_clk_mipibif),
+	MUX("uartape", mux_pllp_pllc_clkm, CLK_SOURCE_UARTAPE, 212, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_uartape),
+	MUX8("tsecb", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_TSECB, 206, 0, tegra_clk_tsecb),
+	MUX8("maud", mux_pllp_pllp_out3_clkm_clk32k_plla, CLK_SOURCE_MAUD, 202, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_maud),
 };
 
 static struct tegra_periph_init_data gate_clks[] = {
@@ -543,6 +823,16 @@
 	GATE("pcie", "clk_m", 70, 0, tegra_clk_pcie, 0),
 	GATE("dpaux", "clk_m", 181, 0, tegra_clk_dpaux, 0),
 	GATE("gpu", "pll_ref", 184, 0, tegra_clk_gpu, 0),
+	GATE("pllg_ref", "pll_ref", 189, 0, tegra_clk_pll_g_ref, 0),
+	GATE("hsic_trk", "usb2_hsic_trk", 209, TEGRA_PERIPH_NO_RESET, tegra_clk_hsic_trk, 0),
+	GATE("usb2_trk", "usb2_hsic_trk", 210, TEGRA_PERIPH_NO_RESET, tegra_clk_usb2_trk, 0),
+	GATE("xusb_gate", "osc", 143, 0, tegra_clk_xusb_gate, 0),
+	GATE("pll_p_out_cpu", "pll_p", 223, 0, tegra_clk_pll_p_out_cpu, 0),
+	GATE("pll_p_out_adsp", "pll_p", 187, 0, tegra_clk_pll_p_out_adsp, 0),
+};
+
+static struct tegra_periph_init_data div_clks[] = {
+	DIV8("usb2_hsic_trk", "osc", CLK_SOURCE_USB2_HSIC_TRK, tegra_clk_usb2_hsic_trk, 0),
 };
 
 struct pll_out_data {
@@ -633,6 +923,33 @@
 	}
 }
 
+static void __init div_clk_init(void __iomem *clk_base,
+				struct tegra_clk *tegra_clks)
+{
+	int i;
+	struct clk *clk;
+	struct clk **dt_clk;
+
+	for (i = 0; i < ARRAY_SIZE(div_clks); i++) {
+		struct tegra_periph_init_data *data;
+
+		data = div_clks + i;
+
+		dt_clk = tegra_lookup_dt_id(data->clk_id, tegra_clks);
+		if (!dt_clk)
+			continue;
+
+		clk = tegra_clk_register_divider(data->name,
+				data->p.parent_name, clk_base + data->offset,
+				data->flags, data->periph.divider.flags,
+				data->periph.divider.shift,
+				data->periph.divider.width,
+				data->periph.divider.frac_width,
+				data->periph.divider.lock);
+		*dt_clk = clk;
+	}
+}
+
 static void __init init_pllp(void __iomem *clk_base, void __iomem *pmc_base,
 				struct tegra_clk *tegra_clks,
 				struct tegra_clk_pll_params *pll_params)
@@ -669,6 +986,51 @@
 				data->lock);
 		*dt_clk = clk;
 	}
+
+	dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out_cpu,
+			tegra_clks);
+	if (dt_clk) {
+		/*
+		 * Tegra210 has control on enabling/disabling PLLP branches to
+		 * CPU, register a gate clock "pll_p_out_cpu" for this gating
+		 * function and parent "pll_p_out4" to it, so when we are
+		 * re-parenting CPU off from "pll_p_out4" the PLLP branching to
+		 * CPU can be disabled automatically.
+		 */
+		clk = tegra_clk_register_divider("pll_p_out4_div",
+				"pll_p_out_cpu", clk_base + PLLP_OUTB, 0, 0, 24,
+				8, 1, &PLLP_OUTB_lock);
+
+		dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out4_cpu, tegra_clks);
+		if (dt_clk) {
+			clk = tegra_clk_register_pll_out("pll_p_out4",
+					"pll_p_out4_div", clk_base + PLLP_OUTB,
+					17, 16, CLK_IGNORE_UNUSED |
+					CLK_SET_RATE_PARENT, 0,
+					&PLLP_OUTB_lock);
+			*dt_clk = clk;
+		}
+	}
+
+	dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out_hsio, tegra_clks);
+	if (dt_clk) {
+		/* PLLP_OUT_HSIO */
+		clk = clk_register_gate(NULL, "pll_p_out_hsio", "pll_p",
+				CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+				clk_base + PLLP_MISC1, 29, 0, NULL);
+		*dt_clk = clk;
+	}
+
+	dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out_xusb, tegra_clks);
+	if (dt_clk) {
+		/* PLLP_OUT_XUSB */
+		clk = clk_register_gate(NULL, "pll_p_out_xusb",
+				"pll_p_out_hsio", CLK_SET_RATE_PARENT |
+				CLK_IGNORE_UNUSED, clk_base + PLLP_MISC1, 28, 0,
+				NULL);
+		clk_register_clkdev(clk, "pll_p_out_xusb", NULL);
+		*dt_clk = clk;
+	}
 }
 
 void __init tegra_periph_clk_init(void __iomem *clk_base,
@@ -678,4 +1040,5 @@
 	init_pllp(clk_base, pmc_base, tegra_clks, pll_params);
 	periph_clk_init(clk_base, tegra_clks);
 	gate_clk_init(clk_base, tegra_clks);
+	div_clk_init(clk_base, tegra_clks);
 }
diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c
index 5b1d723..4559a20 100644
--- a/drivers/clk/tegra/clk-tegra-super-gen4.c
+++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
@@ -34,9 +34,25 @@
 #define CCLKLP_BURST_POLICY 0x370
 #define SCLK_BURST_POLICY 0x028
 #define SYSTEM_CLK_RATE 0x030
+#define SCLK_DIVIDER 0x2c
 
 static DEFINE_SPINLOCK(sysrate_lock);
 
+enum tegra_super_gen {
+	gen4 = 4,
+	gen5,
+};
+
+struct tegra_super_gen_info {
+	enum tegra_super_gen gen;
+	const char **sclk_parents;
+	const char **cclk_g_parents;
+	const char **cclk_lp_parents;
+	int num_sclk_parents;
+	int num_cclk_g_parents;
+	int num_cclk_lp_parents;
+};
+
 static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4",
 			       "pll_p", "pll_p_out2", "unused",
 			       "clk_32k", "pll_m_out1" };
@@ -51,21 +67,81 @@
 					 "pll_p", "pll_p_out4", "unused",
 					 "unused", "pll_x", "pll_x_out0" };
 
+const struct tegra_super_gen_info tegra_super_gen_info_gen4 = {
+	.gen = gen4,
+	.sclk_parents = sclk_parents,
+	.cclk_g_parents = cclk_g_parents,
+	.cclk_lp_parents = cclk_lp_parents,
+	.num_sclk_parents = ARRAY_SIZE(sclk_parents),
+	.num_cclk_g_parents = ARRAY_SIZE(cclk_g_parents),
+	.num_cclk_lp_parents = ARRAY_SIZE(cclk_lp_parents),
+};
+
+static const char *sclk_parents_gen5[] = { "clk_m", "pll_c_out1", "pll_c4_out3",
+			       "pll_p", "pll_p_out2", "pll_c4_out1",
+			       "clk_32k", "pll_c4_out2" };
+
+static const char *cclk_g_parents_gen5[] = { "clk_m", "unused", "clk_32k", "unused",
+					"pll_p", "pll_p_out4", "unused",
+					"unused", "pll_x", "unused", "unused",
+					"unused", "unused", "unused", "unused",
+					"dfllCPU_out" };
+
+static const char *cclk_lp_parents_gen5[] = { "clk_m", "unused", "clk_32k", "unused",
+					"pll_p", "pll_p_out4", "unused",
+					"unused", "pll_x", "unused", "unused",
+					"unused", "unused", "unused", "unused",
+					"dfllCPU_out" };
+
+const struct tegra_super_gen_info tegra_super_gen_info_gen5 = {
+	.gen = gen5,
+	.sclk_parents = sclk_parents_gen5,
+	.cclk_g_parents = cclk_g_parents_gen5,
+	.cclk_lp_parents = cclk_lp_parents_gen5,
+	.num_sclk_parents = ARRAY_SIZE(sclk_parents_gen5),
+	.num_cclk_g_parents = ARRAY_SIZE(cclk_g_parents_gen5),
+	.num_cclk_lp_parents = ARRAY_SIZE(cclk_lp_parents_gen5),
+};
+
 static void __init tegra_sclk_init(void __iomem *clk_base,
-				struct tegra_clk *tegra_clks)
+				struct tegra_clk *tegra_clks,
+				const struct tegra_super_gen_info *gen_info)
 {
 	struct clk *clk;
 	struct clk **dt_clk;
 
-	/* SCLK */
-	dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks);
+	/* SCLK_MUX */
+	dt_clk = tegra_lookup_dt_id(tegra_clk_sclk_mux, tegra_clks);
 	if (dt_clk) {
-		clk = tegra_clk_register_super_mux("sclk", sclk_parents,
-						ARRAY_SIZE(sclk_parents),
+		clk = tegra_clk_register_super_mux("sclk_mux",
+						gen_info->sclk_parents,
+						gen_info->num_sclk_parents,
 						CLK_SET_RATE_PARENT,
 						clk_base + SCLK_BURST_POLICY,
 						0, 4, 0, 0, NULL);
 		*dt_clk = clk;
+
+
+		/* SCLK */
+		dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks);
+		if (dt_clk) {
+			clk = clk_register_divider(NULL, "sclk", "sclk_mux", 0,
+						clk_base + SCLK_DIVIDER, 0, 8,
+						0, &sysrate_lock);
+			*dt_clk = clk;
+		}
+	} else {
+		/* SCLK */
+		dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks);
+		if (dt_clk) {
+			clk = tegra_clk_register_super_mux("sclk",
+						gen_info->sclk_parents,
+						gen_info->num_sclk_parents,
+						CLK_SET_RATE_PARENT,
+						clk_base + SCLK_BURST_POLICY,
+						0, 4, 0, 0, NULL);
+			*dt_clk = clk;
+		}
 	}
 
 	/* HCLK */
@@ -95,10 +171,11 @@
 	*dt_clk = clk;
 }
 
-void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
+void __init tegra_super_clk_init(void __iomem *clk_base,
 				void __iomem *pmc_base,
 				struct tegra_clk *tegra_clks,
-				struct tegra_clk_pll_params *params)
+				struct tegra_clk_pll_params *params,
+				const struct tegra_super_gen_info *gen_info)
 {
 	struct clk *clk;
 	struct clk **dt_clk;
@@ -106,28 +183,50 @@
 	/* CCLKG */
 	dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_g, tegra_clks);
 	if (dt_clk) {
-		clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents,
-					ARRAY_SIZE(cclk_g_parents),
+		if (gen_info->gen == gen5) {
+			clk = tegra_clk_register_super_mux("cclk_g",
+					gen_info->cclk_g_parents,
+					gen_info->num_cclk_g_parents,
+					CLK_SET_RATE_PARENT,
+					clk_base + CCLKG_BURST_POLICY,
+					0, 4, 8, 0, NULL);
+		} else {
+			clk = tegra_clk_register_super_mux("cclk_g",
+					gen_info->cclk_g_parents,
+					gen_info->num_cclk_g_parents,
 					CLK_SET_RATE_PARENT,
 					clk_base + CCLKG_BURST_POLICY,
 					0, 4, 0, 0, NULL);
+		}
 		*dt_clk = clk;
 	}
 
 	/* CCLKLP */
 	dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_lp, tegra_clks);
 	if (dt_clk) {
-		clk = tegra_clk_register_super_mux("cclk_lp", cclk_lp_parents,
-					ARRAY_SIZE(cclk_lp_parents),
+		if (gen_info->gen == gen5) {
+			clk = tegra_clk_register_super_mux("cclk_lp",
+					gen_info->cclk_lp_parents,
+					gen_info->num_cclk_lp_parents,
+					CLK_SET_RATE_PARENT,
+					clk_base + CCLKLP_BURST_POLICY,
+					0, 4, 8, 0, NULL);
+		} else {
+			clk = tegra_clk_register_super_mux("cclk_lp",
+					gen_info->cclk_lp_parents,
+					gen_info->num_cclk_lp_parents,
 					CLK_SET_RATE_PARENT,
 					clk_base + CCLKLP_BURST_POLICY,
 					TEGRA_DIVIDER_2, 4, 8, 9, NULL);
+		}
 		*dt_clk = clk;
 	}
 
-	tegra_sclk_init(clk_base, tegra_clks);
+	tegra_sclk_init(clk_base, tegra_clks, gen_info);
 
-#if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC)
+#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
+    defined(CONFIG_ARCH_TEGRA_124_SOC) || \
+    defined(CONFIG_ARCH_TEGRA_210_SOC)
 	/* PLLX */
 	dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x, tegra_clks);
 	if (!dt_clk)
@@ -148,3 +247,20 @@
 #endif
 }
 
+void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
+				void __iomem *pmc_base,
+				struct tegra_clk *tegra_clks,
+				struct tegra_clk_pll_params *params)
+{
+	tegra_super_clk_init(clk_base, pmc_base, tegra_clks, params,
+			     &tegra_super_gen_info_gen4);
+}
+
+void __init tegra_super_clk_gen5_init(void __iomem *clk_base,
+				void __iomem *pmc_base,
+				struct tegra_clk *tegra_clks,
+				struct tegra_clk_pll_params *params)
+{
+	tegra_super_clk_init(clk_base, pmc_base, tegra_clks, params,
+			     &tegra_super_gen_info_gen5);
+}
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index b7d03e9..4a24aa4 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -182,40 +182,40 @@
 	.divp_width = 4,
 };
 
-static struct pdiv_map pllxc_p[] = {
-	{ .pdiv = 1, .hw_val = 0 },
-	{ .pdiv = 2, .hw_val = 1 },
-	{ .pdiv = 3, .hw_val = 2 },
-	{ .pdiv = 4, .hw_val = 3 },
-	{ .pdiv = 5, .hw_val = 4 },
-	{ .pdiv = 6, .hw_val = 5 },
-	{ .pdiv = 8, .hw_val = 6 },
-	{ .pdiv = 10, .hw_val = 7 },
-	{ .pdiv = 12, .hw_val = 8 },
-	{ .pdiv = 16, .hw_val = 9 },
+static const struct pdiv_map pllxc_p[] = {
+	{ .pdiv =  1, .hw_val =  0 },
+	{ .pdiv =  2, .hw_val =  1 },
+	{ .pdiv =  3, .hw_val =  2 },
+	{ .pdiv =  4, .hw_val =  3 },
+	{ .pdiv =  5, .hw_val =  4 },
+	{ .pdiv =  6, .hw_val =  5 },
+	{ .pdiv =  8, .hw_val =  6 },
+	{ .pdiv = 10, .hw_val =  7 },
+	{ .pdiv = 12, .hw_val =  8 },
+	{ .pdiv = 16, .hw_val =  9 },
 	{ .pdiv = 12, .hw_val = 10 },
 	{ .pdiv = 16, .hw_val = 11 },
 	{ .pdiv = 20, .hw_val = 12 },
 	{ .pdiv = 24, .hw_val = 13 },
 	{ .pdiv = 32, .hw_val = 14 },
-	{ .pdiv = 0, .hw_val = 0 },
+	{ .pdiv =  0, .hw_val =  0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
-	{ 12000000, 624000000, 104, 0, 2},
-	{ 12000000, 600000000, 100, 0, 2},
-	{ 13000000, 600000000,  92, 0, 2},	/* actual: 598.0 MHz */
-	{ 16800000, 600000000,  71, 0, 2},	/* actual: 596.4 MHz */
-	{ 19200000, 600000000,  62, 0, 2},	/* actual: 595.2 MHz */
-	{ 26000000, 600000000,  92, 1, 2},	/* actual: 598.0 MHz */
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000, 624000000, 104, 1, 2, 0 },
+	{ 12000000, 600000000, 100, 1, 2, 0 },
+	{ 13000000, 600000000,  92, 1, 2, 0 }, /* actual: 598.0 MHz */
+	{ 16800000, 600000000,  71, 1, 2, 0 }, /* actual: 596.4 MHz */
+	{ 19200000, 600000000,  62, 1, 2, 0 }, /* actual: 595.2 MHz */
+	{ 26000000, 600000000,  92, 2, 2, 0 }, /* actual: 598.0 MHz */
+	{        0,         0,   0, 0, 0, 0 },
 };
 
 static struct tegra_clk_pll_params pll_c_params = {
 	.input_min = 12000000,
 	.input_max = 800000000,
 	.cf_min = 12000000,
-	.cf_max = 19200000,	/* s/w policy, h/w capability 50 MHz */
+	.cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
 	.vco_min = 600000000,
 	.vco_max = 1400000000,
 	.base_reg = PLLC_BASE,
@@ -232,7 +232,7 @@
 	.pdiv_tohw = pllxc_p,
 	.div_nmp = &pllxc_nmp,
 	.freq_table = pll_c_freq_table,
-	.flags = TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct div_nmp pllcx_nmp = {
@@ -244,22 +244,22 @@
 	.divp_width = 3,
 };
 
-static struct pdiv_map pllc_p[] = {
-	{ .pdiv = 1, .hw_val = 0 },
-	{ .pdiv = 2, .hw_val = 1 },
-	{ .pdiv = 4, .hw_val = 3 },
-	{ .pdiv = 8, .hw_val = 5 },
+static const struct pdiv_map pllc_p[] = {
+	{ .pdiv =  1, .hw_val = 0 },
+	{ .pdiv =  2, .hw_val = 1 },
+	{ .pdiv =  4, .hw_val = 3 },
+	{ .pdiv =  8, .hw_val = 5 },
 	{ .pdiv = 16, .hw_val = 7 },
-	{ .pdiv = 0, .hw_val = 0 },
+	{ .pdiv =  0, .hw_val = 0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_cx_freq_table[] = {
-	{12000000, 600000000, 100, 0, 2},
-	{13000000, 600000000, 92, 0, 2},	/* actual: 598.0 MHz */
-	{16800000, 600000000, 71, 0, 2},	/* actual: 596.4 MHz */
-	{19200000, 600000000, 62, 0, 2},	/* actual: 595.2 MHz */
-	{26000000, 600000000, 92, 1, 2},	/* actual: 598.0 MHz */
-	{0, 0, 0, 0, 0, 0},
+	{ 12000000, 600000000, 100, 1, 2, 0 },
+	{ 13000000, 600000000,  92, 1, 2, 0 }, /* actual: 598.0 MHz */
+	{ 16800000, 600000000,  71, 1, 2, 0 }, /* actual: 596.4 MHz */
+	{ 19200000, 600000000,  62, 1, 2, 0 }, /* actual: 595.2 MHz */
+	{ 26000000, 600000000,  92, 2, 2, 0 }, /* actual: 598.0 MHz */
+	{        0,         0,   0, 0, 0, 0 },
 };
 
 static struct tegra_clk_pll_params pll_c2_params = {
@@ -318,26 +318,26 @@
 	.override_divp_shift = 27,
 };
 
-static struct pdiv_map pllm_p[] = {
+static const struct pdiv_map pllm_p[] = {
 	{ .pdiv = 1, .hw_val = 0 },
 	{ .pdiv = 2, .hw_val = 1 },
 	{ .pdiv = 0, .hw_val = 0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
-	{12000000, 800000000, 66, 0, 1},	/* actual: 792.0 MHz */
-	{13000000, 800000000, 61, 0, 1},	/* actual: 793.0 MHz */
-	{16800000, 800000000, 47, 0, 1},	/* actual: 789.6 MHz */
-	{19200000, 800000000, 41, 0, 1},	/* actual: 787.2 MHz */
-	{26000000, 800000000, 61, 1, 1},	/* actual: 793.0 MHz */
-	{0, 0, 0, 0, 0, 0},
+	{ 12000000, 800000000, 66, 1, 1, 0 }, /* actual: 792.0 MHz */
+	{ 13000000, 800000000, 61, 1, 1, 0 }, /* actual: 793.0 MHz */
+	{ 16800000, 800000000, 47, 1, 1, 0 }, /* actual: 789.6 MHz */
+	{ 19200000, 800000000, 41, 1, 1, 0 }, /* actual: 787.2 MHz */
+	{ 26000000, 800000000, 61, 2, 1, 0 }, /* actual: 793.0 MHz */
+	{        0,         0,  0, 0, 0, 0 },
 };
 
 static struct tegra_clk_pll_params pll_m_params = {
 	.input_min = 12000000,
 	.input_max = 500000000,
 	.cf_min = 12000000,
-	.cf_max = 19200000,	/* s/w policy, h/w capability 50 MHz */
+	.cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
 	.vco_min = 400000000,
 	.vco_max = 1066000000,
 	.base_reg = PLLM_BASE,
@@ -351,7 +351,8 @@
 	.pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
 	.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
 	.freq_table = pll_m_freq_table,
-	.flags = TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
+		 TEGRA_PLL_FIXED,
 };
 
 static struct div_nmp pllp_nmp = {
@@ -364,12 +365,12 @@
 };
 
 static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
-	{12000000, 216000000, 432, 12, 1, 8},
-	{13000000, 216000000, 432, 13, 1, 8},
-	{16800000, 216000000, 360, 14, 1, 8},
-	{19200000, 216000000, 360, 16, 1, 8},
-	{26000000, 216000000, 432, 26, 1, 8},
-	{0, 0, 0, 0, 0, 0},
+	{ 12000000, 216000000, 432, 12, 2, 8 },
+	{ 13000000, 216000000, 432, 13, 2, 8 },
+	{ 16800000, 216000000, 360, 14, 2, 8 },
+	{ 19200000, 216000000, 360, 16, 2, 8 },
+	{ 26000000, 216000000, 432, 26, 2, 8 },
+	{        0,         0,   0,  0, 0, 0 },
 };
 
 static struct tegra_clk_pll_params pll_p_params = {
@@ -386,19 +387,19 @@
 	.lock_delay = 300,
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_p_freq_table,
-	.flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK |
+		 TEGRA_PLL_HAS_LOCK_ENABLE,
 	.fixed_rate = 408000000,
 };
 
 static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
-	{9600000, 282240000, 147, 5, 0, 4},
-	{9600000, 368640000, 192, 5, 0, 4},
-	{9600000, 240000000, 200, 8, 0, 8},
-
-	{28800000, 282240000, 245, 25, 0, 8},
-	{28800000, 368640000, 320, 25, 0, 8},
-	{28800000, 240000000, 200, 24, 0, 8},
-	{0, 0, 0, 0, 0, 0},
+	{  9600000, 282240000, 147,  5, 1, 4 },
+	{  9600000, 368640000, 192,  5, 1, 4 },
+	{  9600000, 240000000, 200,  8, 1, 8 },
+	{ 28800000, 282240000, 245, 25, 1, 8 },
+	{ 28800000, 368640000, 320, 25, 1, 8 },
+	{ 28800000, 240000000, 200, 24, 1, 8 },
+	{        0,         0,   0,  0, 0, 0 },
 };
 
 
@@ -416,28 +417,26 @@
 	.lock_delay = 300,
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_a_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
+		 TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
-	{12000000, 216000000, 864, 12, 2, 12},
-	{13000000, 216000000, 864, 13, 2, 12},
-	{16800000, 216000000, 720, 14, 2, 12},
-	{19200000, 216000000, 720, 16, 2, 12},
-	{26000000, 216000000, 864, 26, 2, 12},
-
-	{12000000, 594000000, 594, 12, 0, 12},
-	{13000000, 594000000, 594, 13, 0, 12},
-	{16800000, 594000000, 495, 14, 0, 12},
-	{19200000, 594000000, 495, 16, 0, 12},
-	{26000000, 594000000, 594, 26, 0, 12},
-
-	{12000000, 1000000000, 1000, 12, 0, 12},
-	{13000000, 1000000000, 1000, 13, 0, 12},
-	{19200000, 1000000000, 625, 12, 0, 12},
-	{26000000, 1000000000, 1000, 26, 0, 12},
-
-	{0, 0, 0, 0, 0, 0},
+	{ 12000000,  216000000,  864, 12, 4, 12 },
+	{ 13000000,  216000000,  864, 13, 4, 12 },
+	{ 16800000,  216000000,  720, 14, 4, 12 },
+	{ 19200000,  216000000,  720, 16, 4, 12 },
+	{ 26000000,  216000000,  864, 26, 4, 12 },
+	{ 12000000,  594000000,  594, 12, 1, 12 },
+	{ 13000000,  594000000,  594, 13, 1, 12 },
+	{ 16800000,  594000000,  495, 14, 1, 12 },
+	{ 19200000,  594000000,  495, 16, 1, 12 },
+	{ 26000000,  594000000,  594, 26, 1, 12 },
+	{ 12000000, 1000000000, 1000, 12, 1, 12 },
+	{ 13000000, 1000000000, 1000, 13, 1, 12 },
+	{ 19200000, 1000000000,  625, 12, 1, 12 },
+	{ 26000000, 1000000000, 1000, 26, 1, 12 },
+	{        0,          0,    0,  0, 0,  0 },
 };
 
 static struct tegra_clk_pll_params pll_d_params = {
@@ -455,7 +454,7 @@
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_d_freq_table,
 	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+		 TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_params pll_d2_params = {
@@ -473,10 +472,10 @@
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_d_freq_table,
 	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+		 TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
-static struct pdiv_map pllu_p[] = {
+static const struct pdiv_map pllu_p[] = {
 	{ .pdiv = 1, .hw_val = 1 },
 	{ .pdiv = 2, .hw_val = 0 },
 	{ .pdiv = 0, .hw_val = 0 },
@@ -492,12 +491,12 @@
 };
 
 static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
-	{12000000, 480000000, 960, 12, 0, 12},
-	{13000000, 480000000, 960, 13, 0, 12},
-	{16800000, 480000000, 400, 7, 0, 5},
-	{19200000, 480000000, 200, 4, 0, 3},
-	{26000000, 480000000, 960, 26, 0, 12},
-	{0, 0, 0, 0, 0, 0},
+	{ 12000000, 480000000, 960, 12, 2, 12 },
+	{ 13000000, 480000000, 960, 13, 2, 12 },
+	{ 16800000, 480000000, 400,  7, 2,  5 },
+	{ 19200000, 480000000, 200,  4, 2,  3 },
+	{ 26000000, 480000000, 960, 26, 2, 12 },
+	{        0,         0,   0,  0, 0,  0 },
 };
 
 static struct tegra_clk_pll_params pll_u_params = {
@@ -516,25 +515,24 @@
 	.div_nmp = &pllu_nmp,
 	.freq_table = pll_u_freq_table,
 	.flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+		 TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
 	/* 1 GHz */
-	{12000000, 1000000000, 83, 0, 1},	/* actual: 996.0 MHz */
-	{13000000, 1000000000, 76, 0, 1},	/* actual: 988.0 MHz */
-	{16800000, 1000000000, 59, 0, 1},	/* actual: 991.2 MHz */
-	{19200000, 1000000000, 52, 0, 1},	/* actual: 998.4 MHz */
-	{26000000, 1000000000, 76, 1, 1},	/* actual: 988.0 MHz */
-
-	{0, 0, 0, 0, 0, 0},
+	{ 12000000, 1000000000, 83, 1, 1, 0 }, /* actual: 996.0 MHz */
+	{ 13000000, 1000000000, 76, 1, 1, 0 }, /* actual: 988.0 MHz */
+	{ 16800000, 1000000000, 59, 1, 1, 0 }, /* actual: 991.2 MHz */
+	{ 19200000, 1000000000, 52, 1, 1, 0 }, /* actual: 998.4 MHz */
+	{ 26000000, 1000000000, 76, 2, 1, 0 }, /* actual: 988.0 MHz */
+	{        0,          0,  0, 0, 0, 0 },
 };
 
 static struct tegra_clk_pll_params pll_x_params = {
 	.input_min = 12000000,
 	.input_max = 800000000,
 	.cf_min = 12000000,
-	.cf_max = 19200000,	/* s/w policy, h/w capability 50 MHz */
+	.cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
 	.vco_min = 700000000,
 	.vco_max = 2400000000U,
 	.base_reg = PLLX_BASE,
@@ -551,15 +549,34 @@
 	.pdiv_tohw = pllxc_p,
 	.div_nmp = &pllxc_nmp,
 	.freq_table = pll_x_freq_table,
-	.flags = TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
 	/* PLLE special case: use cpcon field to store cml divider value */
-	{336000000, 100000000, 100, 21, 16, 11},
-	{312000000, 100000000, 200, 26, 24, 13},
-	{12000000, 100000000, 200,  1,  24, 13},
-	{0, 0, 0, 0, 0, 0},
+	{ 336000000, 100000000, 100, 21, 16, 11 },
+	{ 312000000, 100000000, 200, 26, 24, 13 },
+	{  12000000, 100000000, 200,  1, 24, 13 },
+	{         0,         0,   0,  0,  0,  0 },
+};
+
+static const struct pdiv_map plle_p[] = {
+	{ .pdiv =  1, .hw_val =  0 },
+	{ .pdiv =  2, .hw_val =  1 },
+	{ .pdiv =  3, .hw_val =  2 },
+	{ .pdiv =  4, .hw_val =  3 },
+	{ .pdiv =  5, .hw_val =  4 },
+	{ .pdiv =  6, .hw_val =  5 },
+	{ .pdiv =  8, .hw_val =  6 },
+	{ .pdiv = 10, .hw_val =  7 },
+	{ .pdiv = 12, .hw_val =  8 },
+	{ .pdiv = 16, .hw_val =  9 },
+	{ .pdiv = 12, .hw_val = 10 },
+	{ .pdiv = 16, .hw_val = 11 },
+	{ .pdiv = 20, .hw_val = 12 },
+	{ .pdiv = 24, .hw_val = 13 },
+	{ .pdiv = 32, .hw_val = 14 },
+	{ .pdiv =  0, .hw_val =  0 }
 };
 
 static struct div_nmp plle_nmp = {
@@ -584,9 +601,10 @@
 	.lock_mask = PLLE_MISC_LOCK,
 	.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
 	.lock_delay = 300,
+	.pdiv_tohw = plle_p,
 	.div_nmp = &plle_nmp,
 	.freq_table = pll_e_freq_table,
-	.flags = TEGRA_PLL_FIXED,
+	.flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_LOCK_ENABLE,
 	.fixed_rate = 100000000,
 };
 
@@ -614,18 +632,19 @@
 	.iddq_reg = PLLRE_MISC,
 	.iddq_bit_idx = PLLRE_IDDQ_BIT,
 	.div_nmp = &pllre_nmp,
-	.flags = TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
+		 TEGRA_PLL_LOCK_MISC,
 };
 
 /* possible OSC frequencies in Hz */
 static unsigned long tegra114_input_freq[] = {
-	[0] = 13000000,
-	[1] = 16800000,
-	[4] = 19200000,
-	[5] = 38400000,
-	[8] = 12000000,
-	[9] = 48000000,
-	[12] = 260000000,
+	[ 0] = 13000000,
+	[ 1] = 16800000,
+	[ 4] = 19200000,
+	[ 5] = 38400000,
+	[ 8] = 12000000,
+	[ 9] = 48000000,
+	[12] = 26000000,
 };
 
 #define MASK(x) (BIT(x) - 1)
@@ -644,21 +663,27 @@
 };
 
 static const struct utmi_clk_param utmi_parameters[] = {
-	{.osc_frequency = 13000000, .enable_delay_count = 0x02,
-	 .stable_count = 0x33, .active_delay_count = 0x05,
-	 .xtal_freq_count = 0x7F},
-	{.osc_frequency = 19200000, .enable_delay_count = 0x03,
-	 .stable_count = 0x4B, .active_delay_count = 0x06,
-	 .xtal_freq_count = 0xBB},
-	{.osc_frequency = 12000000, .enable_delay_count = 0x02,
-	 .stable_count = 0x2F, .active_delay_count = 0x04,
-	 .xtal_freq_count = 0x76},
-	{.osc_frequency = 26000000, .enable_delay_count = 0x04,
-	 .stable_count = 0x66, .active_delay_count = 0x09,
-	 .xtal_freq_count = 0xFE},
-	{.osc_frequency = 16800000, .enable_delay_count = 0x03,
-	 .stable_count = 0x41, .active_delay_count = 0x0A,
-	 .xtal_freq_count = 0xA4},
+	{
+		.osc_frequency = 13000000, .enable_delay_count = 0x02,
+		.stable_count = 0x33, .active_delay_count = 0x05,
+		.xtal_freq_count = 0x7f
+	}, {
+		.osc_frequency = 19200000, .enable_delay_count = 0x03,
+		.stable_count = 0x4b, .active_delay_count = 0x06,
+		.xtal_freq_count = 0xbb
+	}, {
+		.osc_frequency = 12000000, .enable_delay_count = 0x02,
+		.stable_count = 0x2f, .active_delay_count = 0x04,
+		.xtal_freq_count = 0x76
+	}, {
+		.osc_frequency = 26000000, .enable_delay_count = 0x04,
+		.stable_count = 0x66, .active_delay_count = 0x09,
+		.xtal_freq_count = 0xfe
+	}, {
+		.osc_frequency = 16800000, .enable_delay_count = 0x03,
+		.stable_count = 0x41, .active_delay_count = 0x0a,
+		.xtal_freq_count = 0xa4
+	},
 };
 
 /* peripheral mux definitions */
@@ -965,8 +990,8 @@
 
 static __init void tegra114_utmi_param_configure(void __iomem *clk_base)
 {
+	unsigned int i;
 	u32 reg;
-	int i;
 
 	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
 		if (osc_freq == utmi_parameters[i].osc_frequency)
@@ -1173,7 +1198,7 @@
 {
 	struct clk *clk;
 	struct tegra_periph_init_data *data;
-	int i;
+	unsigned int i;
 
 	/* xusb_ss_div2 */
 	clk = clk_register_fixed_factor(NULL, "xusb_ss_div2", "xusb_ss_src", 0,
@@ -1278,7 +1303,7 @@
 
 static const struct of_device_id pmc_match[] __initconst = {
 	{ .compatible = "nvidia,tegra114-pmc" },
-	{},
+	{ },
 };
 
 /*
@@ -1286,37 +1311,37 @@
  * breaks
  */
 static struct tegra_clk_init_table init_table[] __initdata = {
-	{TEGRA114_CLK_UARTA, TEGRA114_CLK_PLL_P, 408000000, 0},
-	{TEGRA114_CLK_UARTB, TEGRA114_CLK_PLL_P, 408000000, 0},
-	{TEGRA114_CLK_UARTC, TEGRA114_CLK_PLL_P, 408000000, 0},
-	{TEGRA114_CLK_UARTD, TEGRA114_CLK_PLL_P, 408000000, 0},
-	{TEGRA114_CLK_PLL_A, TEGRA114_CLK_CLK_MAX, 564480000, 1},
-	{TEGRA114_CLK_PLL_A_OUT0, TEGRA114_CLK_CLK_MAX, 11289600, 1},
-	{TEGRA114_CLK_EXTERN1, TEGRA114_CLK_PLL_A_OUT0, 0, 1},
-	{TEGRA114_CLK_CLK_OUT_1_MUX, TEGRA114_CLK_EXTERN1, 0, 1},
-	{TEGRA114_CLK_CLK_OUT_1, TEGRA114_CLK_CLK_MAX, 0, 1},
-	{TEGRA114_CLK_I2S0, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA114_CLK_I2S1, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA114_CLK_I2S2, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA114_CLK_I2S3, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA114_CLK_I2S4, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA114_CLK_HOST1X, TEGRA114_CLK_PLL_P, 136000000, 0},
-	{TEGRA114_CLK_DFLL_SOC, TEGRA114_CLK_PLL_P, 51000000, 1},
-	{TEGRA114_CLK_DFLL_REF, TEGRA114_CLK_PLL_P, 51000000, 1},
-	{TEGRA114_CLK_DISP1, TEGRA114_CLK_PLL_P, 0, 0},
-	{TEGRA114_CLK_DISP2, TEGRA114_CLK_PLL_P, 0, 0},
-	{TEGRA114_CLK_GR2D, TEGRA114_CLK_PLL_C2, 300000000, 0},
-	{TEGRA114_CLK_GR3D, TEGRA114_CLK_PLL_C2, 300000000, 0},
-	{TEGRA114_CLK_DSIALP, TEGRA114_CLK_PLL_P, 68000000, 0},
-	{TEGRA114_CLK_DSIBLP, TEGRA114_CLK_PLL_P, 68000000, 0},
-	{TEGRA114_CLK_PLL_RE_VCO, TEGRA114_CLK_CLK_MAX, 612000000, 0},
-	{TEGRA114_CLK_XUSB_SS_SRC, TEGRA114_CLK_PLL_RE_OUT, 122400000, 0},
-	{TEGRA114_CLK_XUSB_FS_SRC, TEGRA114_CLK_PLL_U_48M, 48000000, 0},
-	{TEGRA114_CLK_XUSB_HS_SRC, TEGRA114_CLK_XUSB_SS_DIV2, 61200000, 0},
-	{TEGRA114_CLK_XUSB_FALCON_SRC, TEGRA114_CLK_PLL_P, 204000000, 0},
-	{TEGRA114_CLK_XUSB_HOST_SRC, TEGRA114_CLK_PLL_P, 102000000, 0},
-	/* This MUST be the last entry. */
-	{TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0},
+	{ TEGRA114_CLK_UARTA, TEGRA114_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA114_CLK_UARTB, TEGRA114_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA114_CLK_UARTC, TEGRA114_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA114_CLK_UARTD, TEGRA114_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA114_CLK_PLL_A, TEGRA114_CLK_CLK_MAX, 564480000, 1 },
+	{ TEGRA114_CLK_PLL_A_OUT0, TEGRA114_CLK_CLK_MAX, 11289600, 1 },
+	{ TEGRA114_CLK_EXTERN1, TEGRA114_CLK_PLL_A_OUT0, 0, 1 },
+	{ TEGRA114_CLK_CLK_OUT_1_MUX, TEGRA114_CLK_EXTERN1, 0, 1 },
+	{ TEGRA114_CLK_CLK_OUT_1, TEGRA114_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA114_CLK_I2S0, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA114_CLK_I2S1, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA114_CLK_I2S2, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA114_CLK_I2S3, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA114_CLK_I2S4, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA114_CLK_HOST1X, TEGRA114_CLK_PLL_P, 136000000, 0 },
+	{ TEGRA114_CLK_DFLL_SOC, TEGRA114_CLK_PLL_P, 51000000, 1 },
+	{ TEGRA114_CLK_DFLL_REF, TEGRA114_CLK_PLL_P, 51000000, 1 },
+	{ TEGRA114_CLK_DISP1, TEGRA114_CLK_PLL_P, 0, 0 },
+	{ TEGRA114_CLK_DISP2, TEGRA114_CLK_PLL_P, 0, 0 },
+	{ TEGRA114_CLK_GR2D, TEGRA114_CLK_PLL_C2, 300000000, 0 },
+	{ TEGRA114_CLK_GR3D, TEGRA114_CLK_PLL_C2, 300000000, 0 },
+	{ TEGRA114_CLK_DSIALP, TEGRA114_CLK_PLL_P, 68000000, 0 },
+	{ TEGRA114_CLK_DSIBLP, TEGRA114_CLK_PLL_P, 68000000, 0 },
+	{ TEGRA114_CLK_PLL_RE_VCO, TEGRA114_CLK_CLK_MAX, 612000000, 0 },
+	{ TEGRA114_CLK_XUSB_SS_SRC, TEGRA114_CLK_PLL_RE_OUT, 122400000, 0 },
+	{ TEGRA114_CLK_XUSB_FS_SRC, TEGRA114_CLK_PLL_U_48M, 48000000, 0 },
+	{ TEGRA114_CLK_XUSB_HS_SRC, TEGRA114_CLK_XUSB_SS_DIV2, 61200000, 0 },
+	{ TEGRA114_CLK_XUSB_FALCON_SRC, TEGRA114_CLK_PLL_P, 204000000, 0 },
+	{ TEGRA114_CLK_XUSB_HOST_SRC, TEGRA114_CLK_PLL_P, 102000000, 0 },
+	/* must be the last entry */
+	{ TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0 },
 };
 
 static void __init tegra114_clock_apply_init_table(void)
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index 87975f7..1627258 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -150,13 +150,13 @@
 
 /* possible OSC frequencies in Hz */
 static unsigned long tegra124_input_freq[] = {
-	[0] = 13000000,
-	[1] = 16800000,
-	[4] = 19200000,
-	[5] = 38400000,
-	[8] = 12000000,
-	[9] = 48000000,
-	[12] = 260000000,
+	[ 0] = 13000000,
+	[ 1] = 16800000,
+	[ 4] = 19200000,
+	[ 5] = 38400000,
+	[ 8] = 12000000,
+	[ 9] = 48000000,
+	[12] = 26000000,
 };
 
 static struct div_nmp pllxc_nmp = {
@@ -168,33 +168,33 @@
 	.divp_width = 4,
 };
 
-static struct pdiv_map pllxc_p[] = {
-	{ .pdiv = 1, .hw_val = 0 },
-	{ .pdiv = 2, .hw_val = 1 },
-	{ .pdiv = 3, .hw_val = 2 },
-	{ .pdiv = 4, .hw_val = 3 },
-	{ .pdiv = 5, .hw_val = 4 },
-	{ .pdiv = 6, .hw_val = 5 },
-	{ .pdiv = 8, .hw_val = 6 },
-	{ .pdiv = 10, .hw_val = 7 },
-	{ .pdiv = 12, .hw_val = 8 },
-	{ .pdiv = 16, .hw_val = 9 },
+static const struct pdiv_map pllxc_p[] = {
+	{ .pdiv =  1, .hw_val =  0 },
+	{ .pdiv =  2, .hw_val =  1 },
+	{ .pdiv =  3, .hw_val =  2 },
+	{ .pdiv =  4, .hw_val =  3 },
+	{ .pdiv =  5, .hw_val =  4 },
+	{ .pdiv =  6, .hw_val =  5 },
+	{ .pdiv =  8, .hw_val =  6 },
+	{ .pdiv = 10, .hw_val =  7 },
+	{ .pdiv = 12, .hw_val =  8 },
+	{ .pdiv = 16, .hw_val =  9 },
 	{ .pdiv = 12, .hw_val = 10 },
 	{ .pdiv = 16, .hw_val = 11 },
 	{ .pdiv = 20, .hw_val = 12 },
 	{ .pdiv = 24, .hw_val = 13 },
 	{ .pdiv = 32, .hw_val = 14 },
-	{ .pdiv = 0, .hw_val = 0 },
+	{ .pdiv =  0, .hw_val =  0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
 	/* 1 GHz */
-	{12000000, 1000000000, 83, 0, 1},	/* actual: 996.0 MHz */
-	{13000000, 1000000000, 76, 0, 1},	/* actual: 988.0 MHz */
-	{16800000, 1000000000, 59, 0, 1},	/* actual: 991.2 MHz */
-	{19200000, 1000000000, 52, 0, 1},	/* actual: 998.4 MHz */
-	{26000000, 1000000000, 76, 1, 1},	/* actual: 988.0 MHz */
-	{0, 0, 0, 0, 0, 0},
+	{ 12000000, 1000000000, 83, 1, 1, 0 }, /* actual: 996.0 MHz */
+	{ 13000000, 1000000000, 76, 1, 1, 0 }, /* actual: 988.0 MHz */
+	{ 16800000, 1000000000, 59, 1, 1, 0 }, /* actual: 991.2 MHz */
+	{ 19200000, 1000000000, 52, 1, 1, 0 }, /* actual: 998.4 MHz */
+	{ 26000000, 1000000000, 76, 2, 1, 0 }, /* actual: 988.0 MHz */
+	{        0,          0,  0, 0, 0, 0 },
 };
 
 static struct tegra_clk_pll_params pll_x_params = {
@@ -218,24 +218,24 @@
 	.pdiv_tohw = pllxc_p,
 	.div_nmp = &pllxc_nmp,
 	.freq_table = pll_x_freq_table,
-	.flags = TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
-	{ 12000000, 624000000, 104, 1, 2},
-	{ 12000000, 600000000, 100, 1, 2},
-	{ 13000000, 600000000,  92, 1, 2},	/* actual: 598.0 MHz */
-	{ 16800000, 600000000,  71, 1, 2},	/* actual: 596.4 MHz */
-	{ 19200000, 600000000,  62, 1, 2},	/* actual: 595.2 MHz */
-	{ 26000000, 600000000,  92, 2, 2},	/* actual: 598.0 MHz */
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000, 624000000, 104, 1, 2, 0 },
+	{ 12000000, 600000000, 100, 1, 2, 0 },
+	{ 13000000, 600000000,  92, 1, 2, 0 }, /* actual: 598.0 MHz */
+	{ 16800000, 600000000,  71, 1, 2, 0 }, /* actual: 596.4 MHz */
+	{ 19200000, 600000000,  62, 1, 2, 0 }, /* actual: 595.2 MHz */
+	{ 26000000, 600000000,  92, 2, 2, 0 }, /* actual: 598.0 MHz */
+	{        0,         0,   0, 0, 0, 0 },
 };
 
 static struct tegra_clk_pll_params pll_c_params = {
 	.input_min = 12000000,
 	.input_max = 800000000,
 	.cf_min = 12000000,
-	.cf_max = 19200000,	/* s/w policy, h/w capability 50 MHz */
+	.cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
 	.vco_min = 600000000,
 	.vco_max = 1400000000,
 	.base_reg = PLLC_BASE,
@@ -252,7 +252,7 @@
 	.pdiv_tohw = pllxc_p,
 	.div_nmp = &pllxc_nmp,
 	.freq_table = pll_c_freq_table,
-	.flags = TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct div_nmp pllcx_nmp = {
@@ -264,25 +264,25 @@
 	.divp_width = 3,
 };
 
-static struct pdiv_map pllc_p[] = {
-	{ .pdiv = 1, .hw_val = 0 },
-	{ .pdiv = 2, .hw_val = 1 },
-	{ .pdiv = 3, .hw_val = 2 },
-	{ .pdiv = 4, .hw_val = 3 },
-	{ .pdiv = 6, .hw_val = 4 },
-	{ .pdiv = 8, .hw_val = 5 },
+static const struct pdiv_map pllc_p[] = {
+	{ .pdiv =  1, .hw_val = 0 },
+	{ .pdiv =  2, .hw_val = 1 },
+	{ .pdiv =  3, .hw_val = 2 },
+	{ .pdiv =  4, .hw_val = 3 },
+	{ .pdiv =  6, .hw_val = 4 },
+	{ .pdiv =  8, .hw_val = 5 },
 	{ .pdiv = 12, .hw_val = 6 },
 	{ .pdiv = 16, .hw_val = 7 },
-	{ .pdiv = 0, .hw_val = 0 },
+	{ .pdiv =  0, .hw_val = 0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_cx_freq_table[] = {
-	{12000000, 600000000, 100, 1, 2},
-	{13000000, 600000000, 92, 1, 2},	/* actual: 598.0 MHz */
-	{16800000, 600000000, 71, 1, 2},	/* actual: 596.4 MHz */
-	{19200000, 600000000, 62, 1, 2},	/* actual: 595.2 MHz */
-	{26000000, 600000000, 92, 2, 2},	/* actual: 598.0 MHz */
-	{0, 0, 0, 0, 0, 0},
+	{ 12000000, 600000000, 100, 1, 2, 0 },
+	{ 13000000, 600000000,  92, 1, 2, 0 }, /* actual: 598.0 MHz */
+	{ 16800000, 600000000,  71, 1, 2, 0 }, /* actual: 596.4 MHz */
+	{ 19200000, 600000000,  62, 1, 2, 0 }, /* actual: 595.2 MHz */
+	{ 26000000, 600000000,  92, 2, 2, 0 }, /* actual: 598.0 MHz */
+	{        0,         0,   0, 0, 0, 0 },
 };
 
 static struct tegra_clk_pll_params pll_c2_params = {
@@ -338,32 +338,32 @@
 	.divp_width = 4,
 };
 
-static struct pdiv_map pll12g_ssd_esd_p[] = {
-	{ .pdiv = 1, .hw_val = 0 },
-	{ .pdiv = 2, .hw_val = 1 },
-	{ .pdiv = 3, .hw_val = 2 },
-	{ .pdiv = 4, .hw_val = 3 },
-	{ .pdiv = 5, .hw_val = 4 },
-	{ .pdiv = 6, .hw_val = 5 },
-	{ .pdiv = 8, .hw_val = 6 },
-	{ .pdiv = 10, .hw_val = 7 },
-	{ .pdiv = 12, .hw_val = 8 },
-	{ .pdiv = 16, .hw_val = 9 },
+static const struct pdiv_map pll12g_ssd_esd_p[] = {
+	{ .pdiv =  1, .hw_val =  0 },
+	{ .pdiv =  2, .hw_val =  1 },
+	{ .pdiv =  3, .hw_val =  2 },
+	{ .pdiv =  4, .hw_val =  3 },
+	{ .pdiv =  5, .hw_val =  4 },
+	{ .pdiv =  6, .hw_val =  5 },
+	{ .pdiv =  8, .hw_val =  6 },
+	{ .pdiv = 10, .hw_val =  7 },
+	{ .pdiv = 12, .hw_val =  8 },
+	{ .pdiv = 16, .hw_val =  9 },
 	{ .pdiv = 12, .hw_val = 10 },
 	{ .pdiv = 16, .hw_val = 11 },
 	{ .pdiv = 20, .hw_val = 12 },
 	{ .pdiv = 24, .hw_val = 13 },
 	{ .pdiv = 32, .hw_val = 14 },
-	{ .pdiv = 0, .hw_val = 0 },
+	{ .pdiv =  0, .hw_val =  0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_c4_freq_table[] = {
-	{ 12000000, 600000000, 100, 1, 1},
-	{ 13000000, 600000000,  92, 1, 1},      /* actual: 598.0 MHz */
-	{ 16800000, 600000000,  71, 1, 1},      /* actual: 596.4 MHz */
-	{ 19200000, 600000000,  62, 1, 1},      /* actual: 595.2 MHz */
-	{ 26000000, 600000000,  92, 2, 1},      /* actual: 598.0 MHz */
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000, 600000000, 100, 1, 2, 0 },
+	{ 13000000, 600000000,  92, 1, 2, 0 }, /* actual: 598.0 MHz */
+	{ 16800000, 600000000,  71, 1, 2, 0 }, /* actual: 596.4 MHz */
+	{ 19200000, 600000000,  62, 1, 2, 0 }, /* actual: 595.2 MHz */
+	{ 26000000, 600000000,  92, 2, 2, 0 }, /* actual: 598.0 MHz */
+	{        0,         0,   0, 0, 0, 0 },
 };
 
 static struct tegra_clk_pll_params pll_c4_params = {
@@ -386,21 +386,35 @@
 	.ext_misc_reg[1] = 0x5b0,
 	.ext_misc_reg[2] = 0x5b4,
 	.freq_table = pll_c4_freq_table,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
-static struct pdiv_map pllm_p[] = {
-	{ .pdiv = 1, .hw_val = 0 },
-	{ .pdiv = 2, .hw_val = 1 },
-	{ .pdiv = 0, .hw_val = 0 },
+static const struct pdiv_map pllm_p[] = {
+	{ .pdiv =  1, .hw_val =  0 },
+	{ .pdiv =  2, .hw_val =  1 },
+	{ .pdiv =  3, .hw_val =  2 },
+	{ .pdiv =  4, .hw_val =  3 },
+	{ .pdiv =  5, .hw_val =  4 },
+	{ .pdiv =  6, .hw_val =  5 },
+	{ .pdiv =  8, .hw_val =  6 },
+	{ .pdiv = 10, .hw_val =  7 },
+	{ .pdiv = 12, .hw_val =  8 },
+	{ .pdiv = 16, .hw_val =  9 },
+	{ .pdiv = 12, .hw_val = 10 },
+	{ .pdiv = 16, .hw_val = 11 },
+	{ .pdiv = 20, .hw_val = 12 },
+	{ .pdiv = 24, .hw_val = 13 },
+	{ .pdiv = 32, .hw_val = 14 },
+	{ .pdiv =  0, .hw_val =  0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
-	{12000000, 800000000, 66, 1, 1},	/* actual: 792.0 MHz */
-	{13000000, 800000000, 61, 1, 1},	/* actual: 793.0 MHz */
-	{16800000, 800000000, 47, 1, 1},	/* actual: 789.6 MHz */
-	{19200000, 800000000, 41, 1, 1},	/* actual: 787.2 MHz */
-	{26000000, 800000000, 61, 2, 1},	/* actual: 793.0 MHz */
-	{0, 0, 0, 0, 0, 0},
+	{ 12000000, 800000000, 66, 1, 1, 0 }, /* actual: 792.0 MHz */
+	{ 13000000, 800000000, 61, 1, 1, 0 }, /* actual: 793.0 MHz */
+	{ 16800000, 800000000, 47, 1, 1, 0 }, /* actual: 789.6 MHz */
+	{ 19200000, 800000000, 41, 1, 1, 0 }, /* actual: 787.2 MHz */
+	{ 26000000, 800000000, 61, 2, 1, 0 }, /* actual: 793.0 MHz */
+	{        0,         0,  0, 0, 0, 0},
 };
 
 static struct div_nmp pllm_nmp = {
@@ -427,22 +441,41 @@
 	.lock_mask = PLL_BASE_LOCK,
 	.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
 	.lock_delay = 300,
-	.max_p = 2,
+	.max_p = 5,
 	.pdiv_tohw = pllm_p,
 	.div_nmp = &pllm_nmp,
 	.pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
 	.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
 	.freq_table = pll_m_freq_table,
-	.flags = TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
 	/* PLLE special case: use cpcon field to store cml divider value */
-	{336000000, 100000000, 100, 21, 16, 11},
-	{312000000, 100000000, 200, 26, 24, 13},
-	{13000000,  100000000, 200, 1,  26, 13},
-	{12000000,  100000000, 200, 1,  24, 13},
-	{0, 0, 0, 0, 0, 0},
+	{ 336000000, 100000000, 100, 21, 16, 11 },
+	{ 312000000, 100000000, 200, 26, 24, 13 },
+	{  13000000, 100000000, 200,  1, 26, 13 },
+	{  12000000, 100000000, 200,  1, 24, 13 },
+	{         0,         0,   0,  0,  0,  0 },
+};
+
+static const struct pdiv_map plle_p[] = {
+	{ .pdiv =  1, .hw_val =  0 },
+	{ .pdiv =  2, .hw_val =  1 },
+	{ .pdiv =  3, .hw_val =  2 },
+	{ .pdiv =  4, .hw_val =  3 },
+	{ .pdiv =  5, .hw_val =  4 },
+	{ .pdiv =  6, .hw_val =  5 },
+	{ .pdiv =  8, .hw_val =  6 },
+	{ .pdiv = 10, .hw_val =  7 },
+	{ .pdiv = 12, .hw_val =  8 },
+	{ .pdiv = 16, .hw_val =  9 },
+	{ .pdiv = 12, .hw_val = 10 },
+	{ .pdiv = 16, .hw_val = 11 },
+	{ .pdiv = 20, .hw_val = 12 },
+	{ .pdiv = 24, .hw_val = 13 },
+	{ .pdiv = 32, .hw_val = 14 },
+	{ .pdiv =  1, .hw_val =  0 },
 };
 
 static struct div_nmp plle_nmp = {
@@ -467,9 +500,10 @@
 	.lock_mask = PLLE_MISC_LOCK,
 	.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
 	.lock_delay = 300,
+	.pdiv_tohw = plle_p,
 	.div_nmp = &plle_nmp,
 	.freq_table = pll_e_freq_table,
-	.flags = TEGRA_PLL_FIXED,
+	.flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_LOCK_ENABLE,
 	.fixed_rate = 100000000,
 };
 
@@ -507,7 +541,8 @@
 	.iddq_reg = PLLRE_MISC,
 	.iddq_bit_idx = PLLRE_IDDQ_BIT,
 	.div_nmp = &pllre_nmp,
-	.flags = TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
+		 TEGRA_PLL_LOCK_MISC,
 };
 
 static struct div_nmp pllp_nmp = {
@@ -520,12 +555,12 @@
 };
 
 static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
-	{12000000, 408000000, 408, 12, 0, 8},
-	{13000000, 408000000, 408, 13, 0, 8},
-	{16800000, 408000000, 340, 14, 0, 8},
-	{19200000, 408000000, 340, 16, 0, 8},
-	{26000000, 408000000, 408, 26, 0, 8},
-	{0, 0, 0, 0, 0, 0},
+	{ 12000000, 408000000, 408, 12, 1, 8 },
+	{ 13000000, 408000000, 408, 13, 1, 8 },
+	{ 16800000, 408000000, 340, 14, 1, 8 },
+	{ 19200000, 408000000, 340, 16, 1, 8 },
+	{ 26000000, 408000000, 408, 26, 1, 8 },
+	{        0,         0,   0,  0, 0, 0 },
 };
 
 static struct tegra_clk_pll_params pll_p_params = {
@@ -543,18 +578,18 @@
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_p_freq_table,
 	.fixed_rate = 408000000,
-	.flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK |
+		 TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
-	{9600000, 282240000, 147, 5, 0, 4},
-	{9600000, 368640000, 192, 5, 0, 4},
-	{9600000, 240000000, 200, 8, 0, 8},
-
-	{28800000, 282240000, 245, 25, 0, 8},
-	{28800000, 368640000, 320, 25, 0, 8},
-	{28800000, 240000000, 200, 24, 0, 8},
-	{0, 0, 0, 0, 0, 0},
+	{  9600000, 282240000, 147,  5, 1, 4 },
+	{  9600000, 368640000, 192,  5, 1, 4 },
+	{  9600000, 240000000, 200,  8, 1, 8 },
+	{ 28800000, 282240000, 245, 25, 1, 8 },
+	{ 28800000, 368640000, 320, 25, 1, 8 },
+	{ 28800000, 240000000, 200, 24, 1, 8 },
+	{        0,         0,   0,  0, 0, 0 },
 };
 
 static struct tegra_clk_pll_params pll_a_params = {
@@ -571,7 +606,8 @@
 	.lock_delay = 300,
 	.div_nmp = &pllp_nmp,
 	.freq_table = pll_a_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
+		 TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct div_nmp plld_nmp = {
@@ -584,24 +620,21 @@
 };
 
 static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
-	{12000000, 216000000, 864, 12, 4, 12},
-	{13000000, 216000000, 864, 13, 4, 12},
-	{16800000, 216000000, 720, 14, 4, 12},
-	{19200000, 216000000, 720, 16, 4, 12},
-	{26000000, 216000000, 864, 26, 4, 12},
-
-	{12000000, 594000000, 594, 12, 1, 12},
-	{13000000, 594000000, 594, 13, 1, 12},
-	{16800000, 594000000, 495, 14, 1, 12},
-	{19200000, 594000000, 495, 16, 1, 12},
-	{26000000, 594000000, 594, 26, 1, 12},
-
-	{12000000, 1000000000, 1000, 12, 1, 12},
-	{13000000, 1000000000, 1000, 13, 1, 12},
-	{19200000, 1000000000, 625, 12, 1, 12},
-	{26000000, 1000000000, 1000, 26, 1, 12},
-
-	{0, 0, 0, 0, 0, 0},
+	{ 12000000,  216000000,  864, 12, 4, 12 },
+	{ 13000000,  216000000,  864, 13, 4, 12 },
+	{ 16800000,  216000000,  720, 14, 4, 12 },
+	{ 19200000,  216000000,  720, 16, 4, 12 },
+	{ 26000000,  216000000,  864, 26, 4, 12 },
+	{ 12000000,  594000000,  594, 12, 1, 12 },
+	{ 13000000,  594000000,  594, 13, 1, 12 },
+	{ 16800000,  594000000,  495, 14, 1, 12 },
+	{ 19200000,  594000000,  495, 16, 1, 12 },
+	{ 26000000,  594000000,  594, 26, 1, 12 },
+	{ 12000000, 1000000000, 1000, 12, 1, 12 },
+	{ 13000000, 1000000000, 1000, 13, 1, 12 },
+	{ 19200000, 1000000000,  625, 12, 1, 12 },
+	{ 26000000, 1000000000, 1000, 26, 1, 12 },
+	{        0,          0,    0,  0, 0,  0 },
 };
 
 static struct tegra_clk_pll_params pll_d_params = {
@@ -619,16 +652,16 @@
 	.div_nmp = &plld_nmp,
 	.freq_table = pll_d_freq_table,
 	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+		 TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_freq_table tegra124_pll_d2_freq_table[] = {
-	{ 12000000, 594000000,  99, 1, 2},
-	{ 13000000, 594000000,  91, 1, 2},      /* actual: 591.5 MHz */
-	{ 16800000, 594000000,  71, 1, 2},      /* actual: 596.4 MHz */
-	{ 19200000, 594000000,  62, 1, 2},      /* actual: 595.2 MHz */
-	{ 26000000, 594000000,  91, 2, 2},      /* actual: 591.5 MHz */
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000, 594000000, 99, 1, 2, 0 },
+	{ 13000000, 594000000, 91, 1, 2, 0 }, /* actual: 591.5 MHz */
+	{ 16800000, 594000000, 71, 1, 2, 0 }, /* actual: 596.4 MHz */
+	{ 19200000, 594000000, 62, 1, 2, 0 }, /* actual: 595.2 MHz */
+	{ 26000000, 594000000, 91, 2, 2, 0 }, /* actual: 591.5 MHz */
+	{        0,         0,  0, 0, 0, 0 },
 };
 
 static struct tegra_clk_pll_params tegra124_pll_d2_params = {
@@ -652,15 +685,16 @@
 	.ext_misc_reg[2] = 0x578,
 	.max_p = 15,
 	.freq_table = tegra124_pll_d2_freq_table,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_freq_table pll_dp_freq_table[] = {
-	{ 12000000, 600000000, 100, 1, 1},
-	{ 13000000, 600000000,  92, 1, 1},      /* actual: 598.0 MHz */
-	{ 16800000, 600000000,  71, 1, 1},      /* actual: 596.4 MHz */
-	{ 19200000, 600000000,  62, 1, 1},      /* actual: 595.2 MHz */
-	{ 26000000, 600000000,  92, 2, 1},      /* actual: 598.0 MHz */
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000, 600000000, 100, 1, 2, 0 },
+	{ 13000000, 600000000,  92, 1, 2, 0 }, /* actual: 598.0 MHz */
+	{ 16800000, 600000000,  71, 1, 2, 0 }, /* actual: 596.4 MHz */
+	{ 19200000, 600000000,  62, 1, 2, 0 }, /* actual: 595.2 MHz */
+	{ 26000000, 600000000,  92, 2, 2, 0 }, /* actual: 598.0 MHz */
+	{        0,         0,   0, 0, 0, 0 },
 };
 
 static struct tegra_clk_pll_params pll_dp_params = {
@@ -684,9 +718,10 @@
 	.ext_misc_reg[2] = 0x5a0,
 	.max_p = 5,
 	.freq_table = pll_dp_freq_table,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
-static struct pdiv_map pllu_p[] = {
+static const struct pdiv_map pllu_p[] = {
 	{ .pdiv = 1, .hw_val = 1 },
 	{ .pdiv = 2, .hw_val = 0 },
 	{ .pdiv = 0, .hw_val = 0 },
@@ -702,12 +737,12 @@
 };
 
 static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
-	{12000000, 480000000, 960, 12, 2, 12},
-	{13000000, 480000000, 960, 13, 2, 12},
-	{16800000, 480000000, 400, 7, 2, 5},
-	{19200000, 480000000, 200, 4, 2, 3},
-	{26000000, 480000000, 960, 26, 2, 12},
-	{0, 0, 0, 0, 0, 0},
+	{ 12000000, 480000000, 960, 12, 2, 12 },
+	{ 13000000, 480000000, 960, 13, 2, 12 },
+	{ 16800000, 480000000, 400,  7, 2,  5 },
+	{ 19200000, 480000000, 200,  4, 2,  3 },
+	{ 26000000, 480000000, 960, 26, 2, 12 },
+	{        0,         0,   0,  0, 0,  0 },
 };
 
 static struct tegra_clk_pll_params pll_u_params = {
@@ -726,7 +761,7 @@
 	.div_nmp = &pllu_nmp,
 	.freq_table = pll_u_freq_table,
 	.flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+		 TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 struct utmi_clk_param {
@@ -743,21 +778,27 @@
 };
 
 static const struct utmi_clk_param utmi_parameters[] = {
-	{.osc_frequency = 13000000, .enable_delay_count = 0x02,
-	 .stable_count = 0x33, .active_delay_count = 0x05,
-	 .xtal_freq_count = 0x7F},
-	{.osc_frequency = 19200000, .enable_delay_count = 0x03,
-	 .stable_count = 0x4B, .active_delay_count = 0x06,
-	 .xtal_freq_count = 0xBB},
-	{.osc_frequency = 12000000, .enable_delay_count = 0x02,
-	 .stable_count = 0x2F, .active_delay_count = 0x04,
-	 .xtal_freq_count = 0x76},
-	{.osc_frequency = 26000000, .enable_delay_count = 0x04,
-	 .stable_count = 0x66, .active_delay_count = 0x09,
-	 .xtal_freq_count = 0xFE},
-	{.osc_frequency = 16800000, .enable_delay_count = 0x03,
-	 .stable_count = 0x41, .active_delay_count = 0x0A,
-	 .xtal_freq_count = 0xA4},
+	{
+		.osc_frequency = 13000000, .enable_delay_count = 0x02,
+		.stable_count = 0x33, .active_delay_count = 0x05,
+		.xtal_freq_count = 0x7f
+	}, {
+		.osc_frequency = 19200000, .enable_delay_count = 0x03,
+		.stable_count = 0x4b, .active_delay_count = 0x06,
+		.xtal_freq_count = 0xbb
+	}, {
+		.osc_frequency = 12000000, .enable_delay_count = 0x02,
+		.stable_count = 0x2f, .active_delay_count = 0x04,
+		.xtal_freq_count = 0x76
+	}, {
+		.osc_frequency = 26000000, .enable_delay_count = 0x04,
+		.stable_count = 0x66, .active_delay_count = 0x09,
+		.xtal_freq_count = 0xfe
+	}, {
+		.osc_frequency = 16800000, .enable_delay_count = 0x03,
+		.stable_count = 0x41, .active_delay_count = 0x0a,
+		.xtal_freq_count = 0xa4
+	},
 };
 
 static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
@@ -1024,8 +1065,8 @@
 
 static void tegra124_utmi_param_configure(void __iomem *clk_base)
 {
+	unsigned int i;
 	u32 reg;
-	int i;
 
 	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
 		if (osc_freq == utmi_parameters[i].osc_frequency)
@@ -1356,65 +1397,65 @@
 
 static const struct of_device_id pmc_match[] __initconst = {
 	{ .compatible = "nvidia,tegra124-pmc" },
-	{},
+	{ },
 };
 
 static struct tegra_clk_init_table common_init_table[] __initdata = {
-	{TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 408000000, 0},
-	{TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 408000000, 0},
-	{TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 408000000, 0},
-	{TEGRA124_CLK_UARTD, TEGRA124_CLK_PLL_P, 408000000, 0},
-	{TEGRA124_CLK_PLL_A, TEGRA124_CLK_CLK_MAX, 564480000, 1},
-	{TEGRA124_CLK_PLL_A_OUT0, TEGRA124_CLK_CLK_MAX, 11289600, 1},
-	{TEGRA124_CLK_EXTERN1, TEGRA124_CLK_PLL_A_OUT0, 0, 1},
-	{TEGRA124_CLK_CLK_OUT_1_MUX, TEGRA124_CLK_EXTERN1, 0, 1},
-	{TEGRA124_CLK_CLK_OUT_1, TEGRA124_CLK_CLK_MAX, 0, 1},
-	{TEGRA124_CLK_I2S0, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA124_CLK_I2S1, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA124_CLK_I2S3, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_P, 0, 0},
-	{TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1},
-	{TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0},
-	{TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0},
-	{TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 1},
-	{TEGRA124_CLK_DFLL_SOC, TEGRA124_CLK_PLL_P, 51000000, 1},
-	{TEGRA124_CLK_DFLL_REF, TEGRA124_CLK_PLL_P, 51000000, 1},
-	{TEGRA124_CLK_PLL_C, TEGRA124_CLK_CLK_MAX, 768000000, 0},
-	{TEGRA124_CLK_PLL_C_OUT1, TEGRA124_CLK_CLK_MAX, 100000000, 0},
-	{TEGRA124_CLK_SBC4, TEGRA124_CLK_PLL_P, 12000000, 1},
-	{TEGRA124_CLK_TSEC, TEGRA124_CLK_PLL_C3, 0, 0},
-	{TEGRA124_CLK_MSENC, TEGRA124_CLK_PLL_C3, 0, 0},
-	{TEGRA124_CLK_PLL_RE_VCO, TEGRA124_CLK_CLK_MAX, 672000000, 0},
-	{TEGRA124_CLK_XUSB_SS_SRC, TEGRA124_CLK_PLL_U_480M, 120000000, 0},
-	{TEGRA124_CLK_XUSB_FS_SRC, TEGRA124_CLK_PLL_U_48M, 48000000, 0},
-	{TEGRA124_CLK_XUSB_HS_SRC, TEGRA124_CLK_PLL_U_60M, 60000000, 0},
-	{TEGRA124_CLK_XUSB_FALCON_SRC, TEGRA124_CLK_PLL_RE_OUT, 224000000, 0},
-	{TEGRA124_CLK_XUSB_HOST_SRC, TEGRA124_CLK_PLL_RE_OUT, 112000000, 0},
-	{TEGRA124_CLK_SATA, TEGRA124_CLK_PLL_P, 104000000, 0},
-	{TEGRA124_CLK_SATA_OOB, TEGRA124_CLK_PLL_P, 204000000, 0},
-	{TEGRA124_CLK_MSELECT, TEGRA124_CLK_CLK_MAX, 0, 1},
-	{TEGRA124_CLK_CSITE, TEGRA124_CLK_CLK_MAX, 0, 1},
-	{TEGRA124_CLK_TSENSOR, TEGRA124_CLK_CLK_M, 400000, 0},
-	/* This MUST be the last entry. */
-	{TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
+	{ TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA124_CLK_UARTD, TEGRA124_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA124_CLK_PLL_A, TEGRA124_CLK_CLK_MAX, 564480000, 1 },
+	{ TEGRA124_CLK_PLL_A_OUT0, TEGRA124_CLK_CLK_MAX, 11289600, 1 },
+	{ TEGRA124_CLK_EXTERN1, TEGRA124_CLK_PLL_A_OUT0, 0, 1 },
+	{ TEGRA124_CLK_CLK_OUT_1_MUX, TEGRA124_CLK_EXTERN1, 0, 1 },
+	{ TEGRA124_CLK_CLK_OUT_1, TEGRA124_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA124_CLK_I2S0, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA124_CLK_I2S1, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA124_CLK_I2S3, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_P, 0, 0 },
+	{ TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1 },
+	{ TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0 },
+	{ TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0 },
+	{ TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 1 },
+	{ TEGRA124_CLK_DFLL_SOC, TEGRA124_CLK_PLL_P, 51000000, 1 },
+	{ TEGRA124_CLK_DFLL_REF, TEGRA124_CLK_PLL_P, 51000000, 1 },
+	{ TEGRA124_CLK_PLL_C, TEGRA124_CLK_CLK_MAX, 768000000, 0 },
+	{ TEGRA124_CLK_PLL_C_OUT1, TEGRA124_CLK_CLK_MAX, 100000000, 0 },
+	{ TEGRA124_CLK_SBC4, TEGRA124_CLK_PLL_P, 12000000, 1 },
+	{ TEGRA124_CLK_TSEC, TEGRA124_CLK_PLL_C3, 0, 0 },
+	{ TEGRA124_CLK_MSENC, TEGRA124_CLK_PLL_C3, 0, 0 },
+	{ TEGRA124_CLK_PLL_RE_VCO, TEGRA124_CLK_CLK_MAX, 672000000, 0 },
+	{ TEGRA124_CLK_XUSB_SS_SRC, TEGRA124_CLK_PLL_U_480M, 120000000, 0 },
+	{ TEGRA124_CLK_XUSB_FS_SRC, TEGRA124_CLK_PLL_U_48M, 48000000, 0 },
+	{ TEGRA124_CLK_XUSB_HS_SRC, TEGRA124_CLK_PLL_U_60M, 60000000, 0 },
+	{ TEGRA124_CLK_XUSB_FALCON_SRC, TEGRA124_CLK_PLL_RE_OUT, 224000000, 0 },
+	{ TEGRA124_CLK_XUSB_HOST_SRC, TEGRA124_CLK_PLL_RE_OUT, 112000000, 0 },
+	{ TEGRA124_CLK_SATA, TEGRA124_CLK_PLL_P, 104000000, 0 },
+	{ TEGRA124_CLK_SATA_OOB, TEGRA124_CLK_PLL_P, 204000000, 0 },
+	{ TEGRA124_CLK_MSELECT, TEGRA124_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA124_CLK_CSITE, TEGRA124_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA124_CLK_TSENSOR, TEGRA124_CLK_CLK_M, 400000, 0 },
+	/* must be the last entry */
+	{ TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0 },
 };
 
 static struct tegra_clk_init_table tegra124_init_table[] __initdata = {
-	{TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 0},
-	{TEGRA124_CLK_CCLK_G, TEGRA124_CLK_CLK_MAX, 0, 1},
-	{TEGRA124_CLK_HDA, TEGRA124_CLK_PLL_P, 102000000, 0},
-	{TEGRA124_CLK_HDA2CODEC_2X, TEGRA124_CLK_PLL_P, 48000000, 0},
-	/* This MUST be the last entry. */
-	{TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
+	{ TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 0 },
+	{ TEGRA124_CLK_CCLK_G, TEGRA124_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA124_CLK_HDA, TEGRA124_CLK_PLL_P, 102000000, 0 },
+	{ TEGRA124_CLK_HDA2CODEC_2X, TEGRA124_CLK_PLL_P, 48000000, 0 },
+	/* must be the last entry */
+	{ TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0 },
 };
 
 /* Tegra132 requires the SOC_THERM clock to remain active */
 static struct tegra_clk_init_table tegra132_init_table[] __initdata = {
-	{TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 1},
-	/* This MUST be the last entry. */
-	{TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
+	{ TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 1 },
+	/* must be the last entry */
+	{ TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0 },
 };
 
 static struct tegra_audio_clk_info tegra124_audio_plls[] = {
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index bf004f0..7a48e98 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -166,126 +166,120 @@
 static struct clk **clks;
 
 static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
-	{ 12000000, 600000000, 600, 12, 0, 8 },
-	{ 13000000, 600000000, 600, 13, 0, 8 },
-	{ 19200000, 600000000, 500, 16, 0, 6 },
-	{ 26000000, 600000000, 600, 26, 0, 8 },
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000, 600000000, 600, 12, 1, 8 },
+	{ 13000000, 600000000, 600, 13, 1, 8 },
+	{ 19200000, 600000000, 500, 16, 1, 6 },
+	{ 26000000, 600000000, 600, 26, 1, 8 },
+	{        0,         0,   0,  0, 0, 0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
-	{ 12000000, 666000000, 666, 12, 0, 8},
-	{ 13000000, 666000000, 666, 13, 0, 8},
-	{ 19200000, 666000000, 555, 16, 0, 8},
-	{ 26000000, 666000000, 666, 26, 0, 8},
-	{ 12000000, 600000000, 600, 12, 0, 8},
-	{ 13000000, 600000000, 600, 13, 0, 8},
-	{ 19200000, 600000000, 375, 12, 0, 6},
-	{ 26000000, 600000000, 600, 26, 0, 8},
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000, 666000000, 666, 12, 1, 8 },
+	{ 13000000, 666000000, 666, 13, 1, 8 },
+	{ 19200000, 666000000, 555, 16, 1, 8 },
+	{ 26000000, 666000000, 666, 26, 1, 8 },
+	{ 12000000, 600000000, 600, 12, 1, 8 },
+	{ 13000000, 600000000, 600, 13, 1, 8 },
+	{ 19200000, 600000000, 375, 12, 1, 6 },
+	{ 26000000, 600000000, 600, 26, 1, 8 },
+	{        0,         0,   0,  0, 0, 0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
-	{ 12000000, 216000000, 432, 12, 1, 8},
-	{ 13000000, 216000000, 432, 13, 1, 8},
-	{ 19200000, 216000000, 90,   4, 1, 1},
-	{ 26000000, 216000000, 432, 26, 1, 8},
-	{ 12000000, 432000000, 432, 12, 0, 8},
-	{ 13000000, 432000000, 432, 13, 0, 8},
-	{ 19200000, 432000000, 90,   4, 0, 1},
-	{ 26000000, 432000000, 432, 26, 0, 8},
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000, 216000000, 432, 12, 2, 8 },
+	{ 13000000, 216000000, 432, 13, 2, 8 },
+	{ 19200000, 216000000,  90,  4, 2, 1 },
+	{ 26000000, 216000000, 432, 26, 2, 8 },
+	{ 12000000, 432000000, 432, 12, 1, 8 },
+	{ 13000000, 432000000, 432, 13, 1, 8 },
+	{ 19200000, 432000000,  90,  4, 1, 1 },
+	{ 26000000, 432000000, 432, 26, 1, 8 },
+	{        0,         0,   0,  0, 0, 0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
-	{ 28800000, 56448000, 49, 25, 0, 1},
-	{ 28800000, 73728000, 64, 25, 0, 1},
-	{ 28800000, 24000000,  5,  6, 0, 1},
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 28800000, 56448000, 49, 25, 1, 1 },
+	{ 28800000, 73728000, 64, 25, 1, 1 },
+	{ 28800000, 24000000,  5,  6, 1, 1 },
+	{        0,        0,  0,  0, 0, 0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
-	{ 12000000, 216000000, 216, 12, 0, 4},
-	{ 13000000, 216000000, 216, 13, 0, 4},
-	{ 19200000, 216000000, 135, 12, 0, 3},
-	{ 26000000, 216000000, 216, 26, 0, 4},
-
-	{ 12000000, 594000000, 594, 12, 0, 8},
-	{ 13000000, 594000000, 594, 13, 0, 8},
-	{ 19200000, 594000000, 495, 16, 0, 8},
-	{ 26000000, 594000000, 594, 26, 0, 8},
-
-	{ 12000000, 1000000000, 1000, 12, 0, 12},
-	{ 13000000, 1000000000, 1000, 13, 0, 12},
-	{ 19200000, 1000000000, 625,  12, 0, 8},
-	{ 26000000, 1000000000, 1000, 26, 0, 12},
-
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000,  216000000,  216, 12, 1,  4 },
+	{ 13000000,  216000000,  216, 13, 1,  4 },
+	{ 19200000,  216000000,  135, 12, 1,  3 },
+	{ 26000000,  216000000,  216, 26, 1,  4 },
+	{ 12000000,  594000000,  594, 12, 1,  8 },
+	{ 13000000,  594000000,  594, 13, 1,  8 },
+	{ 19200000,  594000000,  495, 16, 1,  8 },
+	{ 26000000,  594000000,  594, 26, 1,  8 },
+	{ 12000000, 1000000000, 1000, 12, 1, 12 },
+	{ 13000000, 1000000000, 1000, 13, 1, 12 },
+	{ 19200000, 1000000000,  625, 12, 1,  8 },
+	{ 26000000, 1000000000, 1000, 26, 1, 12 },
+	{        0,          0,    0,  0, 0,  0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
-	{ 12000000, 480000000, 960, 12, 0, 0},
-	{ 13000000, 480000000, 960, 13, 0, 0},
-	{ 19200000, 480000000, 200, 4,  0, 0},
-	{ 26000000, 480000000, 960, 26, 0, 0},
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000, 480000000, 960, 12, 1, 0 },
+	{ 13000000, 480000000, 960, 13, 1, 0 },
+	{ 19200000, 480000000, 200,  4, 1, 0 },
+	{ 26000000, 480000000, 960, 26, 1, 0 },
+	{        0,         0,   0,  0, 0, 0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
 	/* 1 GHz */
-	{ 12000000, 1000000000, 1000, 12, 0, 12},
-	{ 13000000, 1000000000, 1000, 13, 0, 12},
-	{ 19200000, 1000000000, 625,  12, 0, 8},
-	{ 26000000, 1000000000, 1000, 26, 0, 12},
-
+	{ 12000000, 1000000000, 1000, 12, 1, 12 },
+	{ 13000000, 1000000000, 1000, 13, 1, 12 },
+	{ 19200000, 1000000000,  625, 12, 1,  8 },
+	{ 26000000, 1000000000, 1000, 26, 1, 12 },
 	/* 912 MHz */
-	{ 12000000, 912000000,  912,  12, 0, 12},
-	{ 13000000, 912000000,  912,  13, 0, 12},
-	{ 19200000, 912000000,  760,  16, 0, 8},
-	{ 26000000, 912000000,  912,  26, 0, 12},
-
+	{ 12000000,  912000000,  912, 12, 1, 12 },
+	{ 13000000,  912000000,  912, 13, 1, 12 },
+	{ 19200000,  912000000,  760, 16, 1,  8 },
+	{ 26000000,  912000000,  912, 26, 1, 12 },
 	/* 816 MHz */
-	{ 12000000, 816000000,  816,  12, 0, 12},
-	{ 13000000, 816000000,  816,  13, 0, 12},
-	{ 19200000, 816000000,  680,  16, 0, 8},
-	{ 26000000, 816000000,  816,  26, 0, 12},
-
+	{ 12000000,  816000000,  816, 12, 1, 12 },
+	{ 13000000,  816000000,  816, 13, 1, 12 },
+	{ 19200000,  816000000,  680, 16, 1,  8 },
+	{ 26000000,  816000000,  816, 26, 1, 12 },
 	/* 760 MHz */
-	{ 12000000, 760000000,  760,  12, 0, 12},
-	{ 13000000, 760000000,  760,  13, 0, 12},
-	{ 19200000, 760000000,  950,  24, 0, 8},
-	{ 26000000, 760000000,  760,  26, 0, 12},
-
+	{ 12000000,  760000000,  760, 12, 1, 12 },
+	{ 13000000,  760000000,  760, 13, 1, 12 },
+	{ 19200000,  760000000,  950, 24, 1,  8 },
+	{ 26000000,  760000000,  760, 26, 1, 12 },
 	/* 750 MHz */
-	{ 12000000, 750000000,  750,  12, 0, 12},
-	{ 13000000, 750000000,  750,  13, 0, 12},
-	{ 19200000, 750000000,  625,  16, 0, 8},
-	{ 26000000, 750000000,  750,  26, 0, 12},
-
+	{ 12000000,  750000000,  750, 12, 1, 12 },
+	{ 13000000,  750000000,  750, 13, 1, 12 },
+	{ 19200000,  750000000,  625, 16, 1,  8 },
+	{ 26000000,  750000000,  750, 26, 1, 12 },
 	/* 608 MHz */
-	{ 12000000, 608000000,  608,  12, 0, 12},
-	{ 13000000, 608000000,  608,  13, 0, 12},
-	{ 19200000, 608000000,  380,  12, 0, 8},
-	{ 26000000, 608000000,  608,  26, 0, 12},
-
+	{ 12000000,  608000000,  608, 12, 1, 12 },
+	{ 13000000,  608000000,  608, 13, 1, 12 },
+	{ 19200000,  608000000,  380, 12, 1,  8 },
+	{ 26000000,  608000000,  608, 26, 1, 12 },
 	/* 456 MHz */
-	{ 12000000, 456000000,  456,  12, 0, 12},
-	{ 13000000, 456000000,  456,  13, 0, 12},
-	{ 19200000, 456000000,  380,  16, 0, 8},
-	{ 26000000, 456000000,  456,  26, 0, 12},
-
+	{ 12000000,  456000000,  456, 12, 1, 12 },
+	{ 13000000,  456000000,  456, 13, 1, 12 },
+	{ 19200000,  456000000,  380, 16, 1,  8 },
+	{ 26000000,  456000000,  456, 26, 1, 12 },
 	/* 312 MHz */
-	{ 12000000, 312000000,  312,  12, 0, 12},
-	{ 13000000, 312000000,  312,  13, 0, 12},
-	{ 19200000, 312000000,  260,  16, 0, 8},
-	{ 26000000, 312000000,  312,  26, 0, 12},
+	{ 12000000,  312000000,  312, 12, 1, 12 },
+	{ 13000000,  312000000,  312, 13, 1, 12 },
+	{ 19200000,  312000000,  260, 16, 1,  8 },
+	{ 26000000,  312000000,  312, 26, 1, 12 },
+	{        0,          0,    0,  0, 0,  0 },
+};
 
-	{ 0, 0, 0, 0, 0, 0 },
+static const struct pdiv_map plle_p[] = {
+	{ .pdiv = 1, .hw_val = 1 },
+	{ .pdiv = 0, .hw_val = 0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
-	{ 12000000, 100000000,  200,  24, 0, 0 },
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000, 100000000, 200, 24, 1, 0 },
+	{        0,         0,   0,  0, 0, 0 },
 };
 
 /* PLL parameters */
@@ -302,7 +296,7 @@
 	.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
 	.lock_delay = 300,
 	.freq_table = pll_c_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_params pll_m_params = {
@@ -318,7 +312,7 @@
 	.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
 	.lock_delay = 300,
 	.freq_table = pll_m_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_params pll_p_params = {
@@ -334,7 +328,8 @@
 	.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
 	.lock_delay = 300,
 	.freq_table = pll_p_freq_table,
-	.flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON,
+	.flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON |
+		 TEGRA_PLL_HAS_LOCK_ENABLE,
 	.fixed_rate =  216000000,
 };
 
@@ -351,7 +346,7 @@
 	.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
 	.lock_delay = 300,
 	.freq_table = pll_a_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_params pll_d_params = {
@@ -367,10 +362,10 @@
 	.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
 	.lock_delay = 1000,
 	.freq_table = pll_d_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
-static struct pdiv_map pllu_p[] = {
+static const struct pdiv_map pllu_p[] = {
 	{ .pdiv = 1, .hw_val = 1 },
 	{ .pdiv = 2, .hw_val = 0 },
 	{ .pdiv = 0, .hw_val = 0 },
@@ -390,7 +385,7 @@
 	.lock_delay = 1000,
 	.pdiv_tohw = pllu_p,
 	.freq_table = pll_u_freq_table,
-	.flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON,
+	.flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_params pll_x_params = {
@@ -406,7 +401,7 @@
 	.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
 	.lock_delay = 300,
 	.freq_table = pll_x_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_params pll_e_params = {
@@ -421,8 +416,10 @@
 	.lock_mask = PLLE_MISC_LOCK,
 	.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
 	.lock_delay = 0,
+	.pdiv_tohw = plle_p,
 	.freq_table = pll_e_freq_table,
-	.flags = TEGRA_PLL_FIXED,
+	.flags = TEGRA_PLL_FIXED | TEGRA_PLL_LOCK_MISC |
+		 TEGRA_PLL_HAS_LOCK_ENABLE,
 	.fixed_rate = 100000000,
 };
 
@@ -733,9 +730,9 @@
 	clks[TEGRA20_CLK_TWD] = clk;
 }
 
-static const char *audio_parents[] = {"spdif_in", "i2s1", "i2s2", "unused",
-				      "pll_a_out0", "unused", "unused",
-				      "unused"};
+static const char *audio_parents[] = { "spdif_in", "i2s1", "i2s2", "unused",
+				       "pll_a_out0", "unused", "unused",
+				       "unused" };
 
 static void __init tegra20_audio_clk_init(void)
 {
@@ -759,19 +756,18 @@
 				    CLK_SET_RATE_PARENT, 89,
 				    periph_clk_enb_refcnt);
 	clks[TEGRA20_CLK_AUDIO_2X] = clk;
-
 }
 
-static const char *i2s1_parents[] = {"pll_a_out0", "audio_2x", "pll_p",
-				     "clk_m"};
-static const char *i2s2_parents[] = {"pll_a_out0", "audio_2x", "pll_p",
-				     "clk_m"};
-static const char *pwm_parents[] = {"pll_p", "pll_c", "audio", "clk_m",
-				    "clk_32k"};
-static const char *mux_pllpcm_clkm[] = {"pll_p", "pll_c", "pll_m", "clk_m"};
-static const char *mux_pllpdc_clkm[] = {"pll_p", "pll_d_out0", "pll_c",
-					"clk_m"};
-static const char *mux_pllmcp_clkm[] = {"pll_m", "pll_c", "pll_p", "clk_m"};
+static const char *i2s1_parents[] = { "pll_a_out0", "audio_2x", "pll_p",
+				      "clk_m" };
+static const char *i2s2_parents[] = { "pll_a_out0", "audio_2x", "pll_p",
+				      "clk_m" };
+static const char *pwm_parents[] = { "pll_p", "pll_c", "audio", "clk_m",
+				     "clk_32k" };
+static const char *mux_pllpcm_clkm[] = { "pll_p", "pll_c", "pll_m", "clk_m" };
+static const char *mux_pllpdc_clkm[] = { "pll_p", "pll_d_out0", "pll_c",
+					 "clk_m" };
+static const char *mux_pllmcp_clkm[] = { "pll_m", "pll_c", "pll_p", "clk_m" };
 
 static struct tegra_periph_init_data tegra_periph_clk_list[] = {
 	TEGRA_INIT_DATA_MUX("i2s1", i2s1_parents,     CLK_SOURCE_I2S1,   11, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_I2S1),
@@ -802,7 +798,7 @@
 {
 	struct tegra_periph_init_data *data;
 	struct clk *clk;
-	int i;
+	unsigned int i;
 
 	/* ac97 */
 	clk = tegra_clk_register_periph_gate("ac97", "pll_a_out0",
@@ -1025,44 +1021,45 @@
 };
 
 static struct tegra_clk_init_table init_table[] __initdata = {
-	{TEGRA20_CLK_PLL_P, TEGRA20_CLK_CLK_MAX, 216000000, 1},
-	{TEGRA20_CLK_PLL_P_OUT1, TEGRA20_CLK_CLK_MAX, 28800000, 1},
-	{TEGRA20_CLK_PLL_P_OUT2, TEGRA20_CLK_CLK_MAX, 48000000, 1},
-	{TEGRA20_CLK_PLL_P_OUT3, TEGRA20_CLK_CLK_MAX, 72000000, 1},
-	{TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1},
-	{TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 1},
-	{TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 120000000, 1},
-	{TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 0, 1},
-	{TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 0, 1},
-	{TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 1},
-	{TEGRA20_CLK_CSITE, TEGRA20_CLK_CLK_MAX, 0, 1},
-	{TEGRA20_CLK_EMC, TEGRA20_CLK_CLK_MAX, 0, 1},
-	{TEGRA20_CLK_CCLK, TEGRA20_CLK_CLK_MAX, 0, 1},
-	{TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 0},
-	{TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 0},
-	{TEGRA20_CLK_UARTC, TEGRA20_CLK_PLL_P, 0, 0},
-	{TEGRA20_CLK_UARTD, TEGRA20_CLK_PLL_P, 0, 0},
-	{TEGRA20_CLK_UARTE, TEGRA20_CLK_PLL_P, 0, 0},
-	{TEGRA20_CLK_PLL_A, TEGRA20_CLK_CLK_MAX, 56448000, 1},
-	{TEGRA20_CLK_PLL_A_OUT0, TEGRA20_CLK_CLK_MAX, 11289600, 1},
-	{TEGRA20_CLK_CDEV1, TEGRA20_CLK_CLK_MAX, 0, 1},
-	{TEGRA20_CLK_BLINK, TEGRA20_CLK_CLK_MAX, 32768, 1},
-	{TEGRA20_CLK_I2S1, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA20_CLK_I2S2, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA20_CLK_SDMMC1, TEGRA20_CLK_PLL_P, 48000000, 0},
-	{TEGRA20_CLK_SDMMC3, TEGRA20_CLK_PLL_P, 48000000, 0},
-	{TEGRA20_CLK_SDMMC4, TEGRA20_CLK_PLL_P, 48000000, 0},
-	{TEGRA20_CLK_SPI, TEGRA20_CLK_PLL_P, 20000000, 0},
-	{TEGRA20_CLK_SBC1, TEGRA20_CLK_PLL_P, 100000000, 0},
-	{TEGRA20_CLK_SBC2, TEGRA20_CLK_PLL_P, 100000000, 0},
-	{TEGRA20_CLK_SBC3, TEGRA20_CLK_PLL_P, 100000000, 0},
-	{TEGRA20_CLK_SBC4, TEGRA20_CLK_PLL_P, 100000000, 0},
-	{TEGRA20_CLK_HOST1X, TEGRA20_CLK_PLL_C, 150000000, 0},
-	{TEGRA20_CLK_DISP1, TEGRA20_CLK_PLL_P, 600000000, 0},
-	{TEGRA20_CLK_DISP2, TEGRA20_CLK_PLL_P, 600000000, 0},
-	{TEGRA20_CLK_GR2D, TEGRA20_CLK_PLL_C, 300000000, 0},
-	{TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0},
-	{TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0}, /* This MUST be the last entry */
+	{ TEGRA20_CLK_PLL_P, TEGRA20_CLK_CLK_MAX, 216000000, 1 },
+	{ TEGRA20_CLK_PLL_P_OUT1, TEGRA20_CLK_CLK_MAX, 28800000, 1 },
+	{ TEGRA20_CLK_PLL_P_OUT2, TEGRA20_CLK_CLK_MAX, 48000000, 1 },
+	{ TEGRA20_CLK_PLL_P_OUT3, TEGRA20_CLK_CLK_MAX, 72000000, 1 },
+	{ TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1 },
+	{ TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 1 },
+	{ TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 120000000, 1 },
+	{ TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 0, 1 },
+	{ TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 1 },
+	{ TEGRA20_CLK_CSITE, TEGRA20_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA20_CLK_EMC, TEGRA20_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA20_CLK_CCLK, TEGRA20_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 0 },
+	{ TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 0 },
+	{ TEGRA20_CLK_UARTC, TEGRA20_CLK_PLL_P, 0, 0 },
+	{ TEGRA20_CLK_UARTD, TEGRA20_CLK_PLL_P, 0, 0 },
+	{ TEGRA20_CLK_UARTE, TEGRA20_CLK_PLL_P, 0, 0 },
+	{ TEGRA20_CLK_PLL_A, TEGRA20_CLK_CLK_MAX, 56448000, 1 },
+	{ TEGRA20_CLK_PLL_A_OUT0, TEGRA20_CLK_CLK_MAX, 11289600, 1 },
+	{ TEGRA20_CLK_CDEV1, TEGRA20_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA20_CLK_BLINK, TEGRA20_CLK_CLK_MAX, 32768, 1 },
+	{ TEGRA20_CLK_I2S1, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA20_CLK_I2S2, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA20_CLK_SDMMC1, TEGRA20_CLK_PLL_P, 48000000, 0 },
+	{ TEGRA20_CLK_SDMMC3, TEGRA20_CLK_PLL_P, 48000000, 0 },
+	{ TEGRA20_CLK_SDMMC4, TEGRA20_CLK_PLL_P, 48000000, 0 },
+	{ TEGRA20_CLK_SPI, TEGRA20_CLK_PLL_P, 20000000, 0 },
+	{ TEGRA20_CLK_SBC1, TEGRA20_CLK_PLL_P, 100000000, 0 },
+	{ TEGRA20_CLK_SBC2, TEGRA20_CLK_PLL_P, 100000000, 0 },
+	{ TEGRA20_CLK_SBC3, TEGRA20_CLK_PLL_P, 100000000, 0 },
+	{ TEGRA20_CLK_SBC4, TEGRA20_CLK_PLL_P, 100000000, 0 },
+	{ TEGRA20_CLK_HOST1X, TEGRA20_CLK_PLL_C, 150000000, 0 },
+	{ TEGRA20_CLK_DISP1, TEGRA20_CLK_PLL_P, 600000000, 0 },
+	{ TEGRA20_CLK_DISP2, TEGRA20_CLK_PLL_P, 600000000, 0 },
+	{ TEGRA20_CLK_GR2D, TEGRA20_CLK_PLL_C, 300000000, 0 },
+	{ TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
+	/* must be the last entry */
+	{ TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
 };
 
 static void __init tegra20_clock_apply_init_table(void)
@@ -1076,16 +1073,17 @@
  * table under two names.
  */
 static struct tegra_clk_duplicate tegra_clk_duplicates[] = {
-	TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD,   "utmip-pad",    NULL),
-	TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD,   "tegra-ehci.0", NULL),
-	TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD,   "tegra-otg",    NULL),
-	TEGRA_CLK_DUPLICATE(TEGRA20_CLK_CCLK,   NULL,           "cpu"),
-	TEGRA_CLK_DUPLICATE(TEGRA20_CLK_CLK_MAX, NULL, NULL), /* Must be the last entry */
+	TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD,    "utmip-pad",     NULL),
+	TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD,    "tegra-ehci.0",  NULL),
+	TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD,    "tegra-otg",     NULL),
+	TEGRA_CLK_DUPLICATE(TEGRA20_CLK_CCLK,    NULL,           "cpu"),
+	/* must be the last entry */
+	TEGRA_CLK_DUPLICATE(TEGRA20_CLK_CLK_MAX, NULL,            NULL),
 };
 
 static const struct of_device_id pmc_match[] __initconst = {
 	{ .compatible = "nvidia,tegra20-pmc" },
-	{},
+	{ },
 };
 
 static void __init tegra20_clock_init(struct device_node *np)
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
new file mode 100644
index 0000000..58514c4
--- /dev/null
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -0,0 +1,2852 @@
+/*
+ * Copyright (c) 2012-2014 NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/clk/tegra.h>
+#include <dt-bindings/clock/tegra210-car.h>
+
+#include "clk.h"
+#include "clk-id.h"
+
+/*
+ * TEGRA210_CAR_BANK_COUNT: the number of peripheral clock register
+ * banks present in the Tegra210 CAR IP block.  The banks are
+ * identified by single letters, e.g.: L, H, U, V, W, X, Y.  See
+ * periph_regs[] in drivers/clk/tegra/clk.c
+ */
+#define TEGRA210_CAR_BANK_COUNT			7
+
+#define CLK_SOURCE_CSITE 0x1d4
+#define CLK_SOURCE_EMC 0x19c
+
+#define PLLC_BASE 0x80
+#define PLLC_OUT 0x84
+#define PLLC_MISC0 0x88
+#define PLLC_MISC1 0x8c
+#define PLLC_MISC2 0x5d0
+#define PLLC_MISC3 0x5d4
+
+#define PLLC2_BASE 0x4e8
+#define PLLC2_MISC0 0x4ec
+#define PLLC2_MISC1 0x4f0
+#define PLLC2_MISC2 0x4f4
+#define PLLC2_MISC3 0x4f8
+
+#define PLLC3_BASE 0x4fc
+#define PLLC3_MISC0 0x500
+#define PLLC3_MISC1 0x504
+#define PLLC3_MISC2 0x508
+#define PLLC3_MISC3 0x50c
+
+#define PLLM_BASE 0x90
+#define PLLM_MISC0 0x9c
+#define PLLM_MISC1 0x98
+#define PLLP_BASE 0xa0
+#define PLLP_MISC0 0xac
+#define PLLP_MISC1 0x680
+#define PLLA_BASE 0xb0
+#define PLLA_MISC0 0xbc
+#define PLLA_MISC1 0xb8
+#define PLLA_MISC2 0x5d8
+#define PLLD_BASE 0xd0
+#define PLLD_MISC0 0xdc
+#define PLLD_MISC1 0xd8
+#define PLLU_BASE 0xc0
+#define PLLU_OUTA 0xc4
+#define PLLU_MISC0 0xcc
+#define PLLU_MISC1 0xc8
+#define PLLX_BASE 0xe0
+#define PLLX_MISC0 0xe4
+#define PLLX_MISC1 0x510
+#define PLLX_MISC2 0x514
+#define PLLX_MISC3 0x518
+#define PLLX_MISC4 0x5f0
+#define PLLX_MISC5 0x5f4
+#define PLLE_BASE 0xe8
+#define PLLE_MISC0 0xec
+#define PLLD2_BASE 0x4b8
+#define PLLD2_MISC0 0x4bc
+#define PLLD2_MISC1 0x570
+#define PLLD2_MISC2 0x574
+#define PLLD2_MISC3 0x578
+#define PLLE_AUX 0x48c
+#define PLLRE_BASE 0x4c4
+#define PLLRE_MISC0 0x4c8
+#define PLLDP_BASE 0x590
+#define PLLDP_MISC 0x594
+
+#define PLLC4_BASE 0x5a4
+#define PLLC4_MISC0 0x5a8
+#define PLLC4_OUT 0x5e4
+#define PLLMB_BASE 0x5e8
+#define PLLMB_MISC0 0x5ec
+#define PLLA1_BASE 0x6a4
+#define PLLA1_MISC0 0x6a8
+#define PLLA1_MISC1 0x6ac
+#define PLLA1_MISC2 0x6b0
+#define PLLA1_MISC3 0x6b4
+
+#define PLLU_IDDQ_BIT 31
+#define PLLCX_IDDQ_BIT 27
+#define PLLRE_IDDQ_BIT 24
+#define PLLA_IDDQ_BIT 25
+#define PLLD_IDDQ_BIT 20
+#define PLLSS_IDDQ_BIT 18
+#define PLLM_IDDQ_BIT 5
+#define PLLMB_IDDQ_BIT 17
+#define PLLXP_IDDQ_BIT 3
+
+#define PLLCX_RESET_BIT 30
+
+#define PLL_BASE_LOCK BIT(27)
+#define PLLCX_BASE_LOCK BIT(26)
+#define PLLE_MISC_LOCK BIT(11)
+#define PLLRE_MISC_LOCK BIT(27)
+
+#define PLL_MISC_LOCK_ENABLE 18
+#define PLLC_MISC_LOCK_ENABLE 24
+#define PLLDU_MISC_LOCK_ENABLE 22
+#define PLLU_MISC_LOCK_ENABLE 29
+#define PLLE_MISC_LOCK_ENABLE 9
+#define PLLRE_MISC_LOCK_ENABLE 30
+#define PLLSS_MISC_LOCK_ENABLE 30
+#define PLLP_MISC_LOCK_ENABLE 18
+#define PLLM_MISC_LOCK_ENABLE 4
+#define PLLMB_MISC_LOCK_ENABLE 16
+#define PLLA_MISC_LOCK_ENABLE 28
+#define PLLU_MISC_LOCK_ENABLE 29
+#define PLLD_MISC_LOCK_ENABLE 18
+
+#define PLLA_SDM_DIN_MASK 0xffff
+#define PLLA_SDM_EN_MASK BIT(26)
+
+#define PLLD_SDM_EN_MASK BIT(16)
+
+#define PLLD2_SDM_EN_MASK BIT(31)
+#define PLLD2_SSC_EN_MASK BIT(30)
+
+#define PLLDP_SS_CFG	0x598
+#define PLLDP_SDM_EN_MASK BIT(31)
+#define PLLDP_SSC_EN_MASK BIT(30)
+#define PLLDP_SS_CTRL1	0x59c
+#define PLLDP_SS_CTRL2	0x5a0
+
+#define PMC_PLLM_WB0_OVERRIDE 0x1dc
+#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0
+
+#define UTMIP_PLL_CFG2 0x488
+#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xfff) << 6)
+#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERUP BIT(1)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERUP BIT(3)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERUP BIT(5)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERDOWN BIT(24)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERUP BIT(25)
+
+#define UTMIP_PLL_CFG1 0x484
+#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
+#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP BIT(17)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP BIT(15)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12)
+
+#define UTMIPLL_HW_PWRDN_CFG0			0x52c
+#define UTMIPLL_HW_PWRDN_CFG0_UTMIPLL_LOCK	BIT(31)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE	BIT(25)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE	BIT(24)
+#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE	BIT(7)
+#define UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET	BIT(6)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_RESET_INPUT_VALUE	BIT(5)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_IN_SWCTL	BIT(4)
+#define UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL	BIT(2)
+#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE	BIT(1)
+#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL	BIT(0)
+
+#define PLLU_HW_PWRDN_CFG0			0x530
+#define PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE	BIT(28)
+#define PLLU_HW_PWRDN_CFG0_SEQ_ENABLE		BIT(24)
+#define PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT	BIT(7)
+#define PLLU_HW_PWRDN_CFG0_USE_LOCKDET		BIT(6)
+#define PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL	BIT(2)
+#define PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL	BIT(0)
+
+#define XUSB_PLL_CFG0				0x534
+#define XUSB_PLL_CFG0_UTMIPLL_LOCK_DLY		0x3ff
+#define XUSB_PLL_CFG0_PLLU_LOCK_DLY_MASK	(0x3ff << 14)
+
+#define SPARE_REG0 0x55c
+#define CLK_M_DIVISOR_SHIFT 2
+#define CLK_M_DIVISOR_MASK 0x3
+
+/*
+ * SDM fractional divisor is 16-bit 2's complement signed number within
+ * (-2^12 ... 2^12-1) range. Represented in PLL data structure as unsigned
+ * 16-bit value, with "0" divisor mapped to 0xFFFF. Data "0" is used to
+ * indicate that SDM is disabled.
+ *
+ * Effective ndiv value when SDM is enabled: ndiv + 1/2 + sdm_din/2^13
+ */
+#define PLL_SDM_COEFF BIT(13)
+#define sdin_din_to_data(din)	((u16)((din) ? : 0xFFFFU))
+#define sdin_data_to_din(dat)	(((dat) == 0xFFFFU) ? 0 : (s16)dat)
+
+/* Tegra CPU clock and reset control regs */
+#define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS	0x470
+
+#ifdef CONFIG_PM_SLEEP
+static struct cpu_clk_suspend_context {
+	u32 clk_csite_src;
+} tegra210_cpu_clk_sctx;
+#endif
+
+static void __iomem *clk_base;
+static void __iomem *pmc_base;
+
+static unsigned long osc_freq;
+static unsigned long pll_ref_freq;
+
+static DEFINE_SPINLOCK(pll_d_lock);
+static DEFINE_SPINLOCK(pll_e_lock);
+static DEFINE_SPINLOCK(pll_re_lock);
+static DEFINE_SPINLOCK(pll_u_lock);
+static DEFINE_SPINLOCK(emc_lock);
+
+/* possible OSC frequencies in Hz */
+static unsigned long tegra210_input_freq[] = {
+	[5] = 38400000,
+	[8] = 12000000,
+};
+
+static const char *mux_pllmcp_clkm[] = {
+	"pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_c2", "pll_c3",
+};
+#define mux_pllmcp_clkm_idx NULL
+
+#define PLL_ENABLE			(1 << 30)
+
+#define PLLCX_MISC1_IDDQ		(1 << 27)
+#define PLLCX_MISC0_RESET		(1 << 30)
+
+#define PLLCX_MISC0_DEFAULT_VALUE	0x40080000
+#define PLLCX_MISC0_WRITE_MASK		0x400ffffb
+#define PLLCX_MISC1_DEFAULT_VALUE	0x08000000
+#define PLLCX_MISC1_WRITE_MASK		0x08003cff
+#define PLLCX_MISC2_DEFAULT_VALUE	0x1f720f05
+#define PLLCX_MISC2_WRITE_MASK		0xffffff17
+#define PLLCX_MISC3_DEFAULT_VALUE	0x000000c4
+#define PLLCX_MISC3_WRITE_MASK		0x00ffffff
+
+/* PLLA */
+#define PLLA_BASE_IDDQ			(1 << 25)
+#define PLLA_BASE_LOCK			(1 << 27)
+
+#define PLLA_MISC0_LOCK_ENABLE		(1 << 28)
+#define PLLA_MISC0_LOCK_OVERRIDE	(1 << 27)
+
+#define PLLA_MISC2_EN_SDM		(1 << 26)
+#define PLLA_MISC2_EN_DYNRAMP		(1 << 25)
+
+#define PLLA_MISC0_DEFAULT_VALUE	0x12000020
+#define PLLA_MISC0_WRITE_MASK		0x7fffffff
+#define PLLA_MISC2_DEFAULT_VALUE	0x0
+#define PLLA_MISC2_WRITE_MASK		0x06ffffff
+
+/* PLLD */
+#define PLLD_MISC0_EN_SDM		(1 << 16)
+#define PLLD_MISC0_LOCK_OVERRIDE	(1 << 17)
+#define PLLD_MISC0_LOCK_ENABLE		(1 << 18)
+#define PLLD_MISC0_IDDQ			(1 << 20)
+#define PLLD_MISC0_DSI_CLKENABLE	(1 << 21)
+
+#define PLLD_MISC0_DEFAULT_VALUE	0x00140000
+#define PLLD_MISC0_WRITE_MASK		0x3ff7ffff
+#define PLLD_MISC1_DEFAULT_VALUE	0x20
+#define PLLD_MISC1_WRITE_MASK		0x00ffffff
+
+/* PLLD2 and PLLDP  and PLLC4 */
+#define PLLDSS_BASE_LOCK		(1 << 27)
+#define PLLDSS_BASE_LOCK_OVERRIDE	(1 << 24)
+#define PLLDSS_BASE_IDDQ		(1 << 18)
+#define PLLDSS_BASE_REF_SEL_SHIFT	25
+#define PLLDSS_BASE_REF_SEL_MASK	(0x3 << PLLDSS_BASE_REF_SEL_SHIFT)
+
+#define PLLDSS_MISC0_LOCK_ENABLE	(1 << 30)
+
+#define PLLDSS_MISC1_CFG_EN_SDM		(1 << 31)
+#define PLLDSS_MISC1_CFG_EN_SSC		(1 << 30)
+
+#define PLLD2_MISC0_DEFAULT_VALUE	0x40000020
+#define PLLD2_MISC1_CFG_DEFAULT_VALUE	0x10000000
+#define PLLD2_MISC2_CTRL1_DEFAULT_VALUE	0x0
+#define PLLD2_MISC3_CTRL2_DEFAULT_VALUE	0x0
+
+#define PLLDP_MISC0_DEFAULT_VALUE	0x40000020
+#define PLLDP_MISC1_CFG_DEFAULT_VALUE	0xc0000000
+#define PLLDP_MISC2_CTRL1_DEFAULT_VALUE	0xf400f0da
+#define PLLDP_MISC3_CTRL2_DEFAULT_VALUE	0x2004f400
+
+#define PLLDSS_MISC0_WRITE_MASK		0x47ffffff
+#define PLLDSS_MISC1_CFG_WRITE_MASK	0xf8000000
+#define PLLDSS_MISC2_CTRL1_WRITE_MASK	0xffffffff
+#define PLLDSS_MISC3_CTRL2_WRITE_MASK	0xffffffff
+
+#define PLLC4_MISC0_DEFAULT_VALUE	0x40000000
+
+/* PLLRE */
+#define PLLRE_MISC0_LOCK_ENABLE		(1 << 30)
+#define PLLRE_MISC0_LOCK_OVERRIDE	(1 << 29)
+#define PLLRE_MISC0_LOCK		(1 << 27)
+#define PLLRE_MISC0_IDDQ		(1 << 24)
+
+#define PLLRE_BASE_DEFAULT_VALUE	0x0
+#define PLLRE_MISC0_DEFAULT_VALUE	0x41000000
+
+#define PLLRE_BASE_DEFAULT_MASK		0x1c000000
+#define PLLRE_MISC0_WRITE_MASK		0x67ffffff
+
+/* PLLX */
+#define PLLX_USE_DYN_RAMP		1
+#define PLLX_BASE_LOCK			(1 << 27)
+
+#define PLLX_MISC0_FO_G_DISABLE		(0x1 << 28)
+#define PLLX_MISC0_LOCK_ENABLE		(0x1 << 18)
+
+#define PLLX_MISC2_DYNRAMP_STEPB_SHIFT	24
+#define PLLX_MISC2_DYNRAMP_STEPB_MASK	(0xFF << PLLX_MISC2_DYNRAMP_STEPB_SHIFT)
+#define PLLX_MISC2_DYNRAMP_STEPA_SHIFT	16
+#define PLLX_MISC2_DYNRAMP_STEPA_MASK	(0xFF << PLLX_MISC2_DYNRAMP_STEPA_SHIFT)
+#define PLLX_MISC2_NDIV_NEW_SHIFT	8
+#define PLLX_MISC2_NDIV_NEW_MASK	(0xFF << PLLX_MISC2_NDIV_NEW_SHIFT)
+#define PLLX_MISC2_LOCK_OVERRIDE	(0x1 << 4)
+#define PLLX_MISC2_DYNRAMP_DONE		(0x1 << 2)
+#define PLLX_MISC2_EN_DYNRAMP		(0x1 << 0)
+
+#define PLLX_MISC3_IDDQ			(0x1 << 3)
+
+#define PLLX_MISC0_DEFAULT_VALUE	PLLX_MISC0_LOCK_ENABLE
+#define PLLX_MISC0_WRITE_MASK		0x10c40000
+#define PLLX_MISC1_DEFAULT_VALUE	0x20
+#define PLLX_MISC1_WRITE_MASK		0x00ffffff
+#define PLLX_MISC2_DEFAULT_VALUE	0x0
+#define PLLX_MISC2_WRITE_MASK		0xffffff11
+#define PLLX_MISC3_DEFAULT_VALUE	PLLX_MISC3_IDDQ
+#define PLLX_MISC3_WRITE_MASK		0x01ff0f0f
+#define PLLX_MISC4_DEFAULT_VALUE	0x0
+#define PLLX_MISC4_WRITE_MASK		0x8000ffff
+#define PLLX_MISC5_DEFAULT_VALUE	0x0
+#define PLLX_MISC5_WRITE_MASK		0x0000ffff
+
+#define PLLX_HW_CTRL_CFG		0x548
+#define PLLX_HW_CTRL_CFG_SWCTRL		(0x1 << 0)
+
+/* PLLMB */
+#define PLLMB_BASE_LOCK			(1 << 27)
+
+#define PLLMB_MISC0_LOCK_OVERRIDE	(1 << 18)
+#define PLLMB_MISC0_IDDQ		(1 << 17)
+#define PLLMB_MISC0_LOCK_ENABLE		(1 << 16)
+
+#define PLLMB_MISC0_DEFAULT_VALUE	0x00030000
+#define PLLMB_MISC0_WRITE_MASK		0x0007ffff
+
+/* PLLP */
+#define PLLP_BASE_OVERRIDE		(1 << 28)
+#define PLLP_BASE_LOCK			(1 << 27)
+
+#define PLLP_MISC0_LOCK_ENABLE		(1 << 18)
+#define PLLP_MISC0_LOCK_OVERRIDE	(1 << 17)
+#define PLLP_MISC0_IDDQ			(1 << 3)
+
+#define PLLP_MISC1_HSIO_EN_SHIFT	29
+#define PLLP_MISC1_HSIO_EN		(1 << PLLP_MISC1_HSIO_EN_SHIFT)
+#define PLLP_MISC1_XUSB_EN_SHIFT	28
+#define PLLP_MISC1_XUSB_EN		(1 << PLLP_MISC1_XUSB_EN_SHIFT)
+
+#define PLLP_MISC0_DEFAULT_VALUE	0x00040008
+#define PLLP_MISC1_DEFAULT_VALUE	0x0
+
+#define PLLP_MISC0_WRITE_MASK		0xdc6000f
+#define PLLP_MISC1_WRITE_MASK		0x70ffffff
+
+/* PLLU */
+#define PLLU_BASE_LOCK			(1 << 27)
+#define PLLU_BASE_OVERRIDE		(1 << 24)
+#define PLLU_BASE_CLKENABLE_USB		(1 << 21)
+#define PLLU_BASE_CLKENABLE_HSIC	(1 << 22)
+#define PLLU_BASE_CLKENABLE_ICUSB	(1 << 23)
+#define PLLU_BASE_CLKENABLE_48M		(1 << 25)
+#define PLLU_BASE_CLKENABLE_ALL		(PLLU_BASE_CLKENABLE_USB |\
+					 PLLU_BASE_CLKENABLE_HSIC |\
+					 PLLU_BASE_CLKENABLE_ICUSB |\
+					 PLLU_BASE_CLKENABLE_48M)
+
+#define PLLU_MISC0_IDDQ			(1 << 31)
+#define PLLU_MISC0_LOCK_ENABLE		(1 << 29)
+#define PLLU_MISC1_LOCK_OVERRIDE	(1 << 0)
+
+#define PLLU_MISC0_DEFAULT_VALUE	0xa0000000
+#define PLLU_MISC1_DEFAULT_VALUE	0x0
+
+#define PLLU_MISC0_WRITE_MASK		0xbfffffff
+#define PLLU_MISC1_WRITE_MASK		0x00000007
+
+static inline void _pll_misc_chk_default(void __iomem *base,
+					struct tegra_clk_pll_params *params,
+					u8 misc_num, u32 default_val, u32 mask)
+{
+	u32 boot_val = readl_relaxed(base + params->ext_misc_reg[misc_num]);
+
+	boot_val &= mask;
+	default_val &= mask;
+	if (boot_val != default_val) {
+		pr_warn("boot misc%d 0x%x: expected 0x%x\n",
+			misc_num, boot_val, default_val);
+		pr_warn(" (comparison mask = 0x%x)\n", mask);
+		params->defaults_set = false;
+	}
+}
+
+/*
+ * PLLCX: PLLC, PLLC2, PLLC3, PLLA1
+ * Hybrid PLLs with dynamic ramp. Dynamic ramp is allowed for any transition
+ * that changes NDIV only, while PLL is already locked.
+ */
+static void pllcx_check_defaults(struct tegra_clk_pll_params *params)
+{
+	u32 default_val;
+
+	default_val = PLLCX_MISC0_DEFAULT_VALUE & (~PLLCX_MISC0_RESET);
+	_pll_misc_chk_default(clk_base, params, 0, default_val,
+			PLLCX_MISC0_WRITE_MASK);
+
+	default_val = PLLCX_MISC1_DEFAULT_VALUE & (~PLLCX_MISC1_IDDQ);
+	_pll_misc_chk_default(clk_base, params, 1, default_val,
+			PLLCX_MISC1_WRITE_MASK);
+
+	default_val = PLLCX_MISC2_DEFAULT_VALUE;
+	_pll_misc_chk_default(clk_base, params, 2, default_val,
+			PLLCX_MISC2_WRITE_MASK);
+
+	default_val = PLLCX_MISC3_DEFAULT_VALUE;
+	_pll_misc_chk_default(clk_base, params, 3, default_val,
+			PLLCX_MISC3_WRITE_MASK);
+}
+
+void tegra210_pllcx_set_defaults(const char *name, struct tegra_clk_pll *pllcx)
+{
+	pllcx->params->defaults_set = true;
+
+	if (readl_relaxed(clk_base + pllcx->params->base_reg) &
+			PLL_ENABLE) {
+		/* PLL is ON: only check if defaults already set */
+		pllcx_check_defaults(pllcx->params);
+		pr_warn("%s already enabled. Postponing set full defaults\n",
+			name);
+		return;
+	}
+
+	/* Defaults assert PLL reset, and set IDDQ */
+	writel_relaxed(PLLCX_MISC0_DEFAULT_VALUE,
+			clk_base + pllcx->params->ext_misc_reg[0]);
+	writel_relaxed(PLLCX_MISC1_DEFAULT_VALUE,
+			clk_base + pllcx->params->ext_misc_reg[1]);
+	writel_relaxed(PLLCX_MISC2_DEFAULT_VALUE,
+			clk_base + pllcx->params->ext_misc_reg[2]);
+	writel_relaxed(PLLCX_MISC3_DEFAULT_VALUE,
+			clk_base + pllcx->params->ext_misc_reg[3]);
+	udelay(1);
+}
+
+void _pllc_set_defaults(struct tegra_clk_pll *pllcx)
+{
+	tegra210_pllcx_set_defaults("PLL_C", pllcx);
+}
+
+void _pllc2_set_defaults(struct tegra_clk_pll *pllcx)
+{
+	tegra210_pllcx_set_defaults("PLL_C2", pllcx);
+}
+
+void _pllc3_set_defaults(struct tegra_clk_pll *pllcx)
+{
+	tegra210_pllcx_set_defaults("PLL_C3", pllcx);
+}
+
+void _plla1_set_defaults(struct tegra_clk_pll *pllcx)
+{
+	tegra210_pllcx_set_defaults("PLL_A1", pllcx);
+}
+
+/*
+ * PLLA
+ * PLL with dynamic ramp and fractional SDM. Dynamic ramp is not used.
+ * Fractional SDM is allowed to provide exact audio rates.
+ */
+void tegra210_plla_set_defaults(struct tegra_clk_pll *plla)
+{
+	u32 mask;
+	u32 val = readl_relaxed(clk_base + plla->params->base_reg);
+
+	plla->params->defaults_set = true;
+
+	if (val & PLL_ENABLE) {
+		/*
+		 * PLL is ON: check if defaults already set, then set those
+		 * that can be updated in flight.
+		 */
+		if (val & PLLA_BASE_IDDQ) {
+			pr_warn("PLL_A boot enabled with IDDQ set\n");
+			plla->params->defaults_set = false;
+		}
+
+		pr_warn("PLL_A already enabled. Postponing set full defaults\n");
+
+		val = PLLA_MISC0_DEFAULT_VALUE;	/* ignore lock enable */
+		mask = PLLA_MISC0_LOCK_ENABLE | PLLA_MISC0_LOCK_OVERRIDE;
+		_pll_misc_chk_default(clk_base, plla->params, 0, val,
+				~mask & PLLA_MISC0_WRITE_MASK);
+
+		val = PLLA_MISC2_DEFAULT_VALUE; /* ignore all but control bit */
+		_pll_misc_chk_default(clk_base, plla->params, 2, val,
+				PLLA_MISC2_EN_DYNRAMP);
+
+		/* Enable lock detect */
+		val = readl_relaxed(clk_base + plla->params->ext_misc_reg[0]);
+		val &= ~mask;
+		val |= PLLA_MISC0_DEFAULT_VALUE & mask;
+		writel_relaxed(val, clk_base + plla->params->ext_misc_reg[0]);
+		udelay(1);
+
+		return;
+	}
+
+	/* set IDDQ, enable lock detect, disable dynamic ramp and SDM */
+	val |= PLLA_BASE_IDDQ;
+	writel_relaxed(val, clk_base + plla->params->base_reg);
+	writel_relaxed(PLLA_MISC0_DEFAULT_VALUE,
+			clk_base + plla->params->ext_misc_reg[0]);
+	writel_relaxed(PLLA_MISC2_DEFAULT_VALUE,
+			clk_base + plla->params->ext_misc_reg[2]);
+	udelay(1);
+}
+
+/*
+ * PLLD
+ * PLL with fractional SDM.
+ */
+void tegra210_plld_set_defaults(struct tegra_clk_pll *plld)
+{
+	u32 val;
+	u32 mask = 0xffff;
+
+	plld->params->defaults_set = true;
+
+	if (readl_relaxed(clk_base + plld->params->base_reg) &
+			PLL_ENABLE) {
+		pr_warn("PLL_D already enabled. Postponing set full defaults\n");
+
+		/*
+		 * PLL is ON: check if defaults already set, then set those
+		 * that can be updated in flight.
+		 */
+		val = PLLD_MISC1_DEFAULT_VALUE;
+		_pll_misc_chk_default(clk_base, plld->params, 1,
+				val, PLLD_MISC1_WRITE_MASK);
+
+		/* ignore lock, DSI and SDM controls, make sure IDDQ not set */
+		val = PLLD_MISC0_DEFAULT_VALUE & (~PLLD_MISC0_IDDQ);
+		mask |= PLLD_MISC0_DSI_CLKENABLE | PLLD_MISC0_LOCK_ENABLE |
+			PLLD_MISC0_LOCK_OVERRIDE | PLLD_MISC0_EN_SDM;
+		_pll_misc_chk_default(clk_base, plld->params, 0, val,
+				~mask & PLLD_MISC0_WRITE_MASK);
+
+		/* Enable lock detect */
+		mask = PLLD_MISC0_LOCK_ENABLE | PLLD_MISC0_LOCK_OVERRIDE;
+		val = readl_relaxed(clk_base + plld->params->ext_misc_reg[0]);
+		val &= ~mask;
+		val |= PLLD_MISC0_DEFAULT_VALUE & mask;
+		writel_relaxed(val, clk_base + plld->params->ext_misc_reg[0]);
+		udelay(1);
+
+		return;
+	}
+
+	val = readl_relaxed(clk_base + plld->params->ext_misc_reg[0]);
+	val &= PLLD_MISC0_DSI_CLKENABLE;
+	val |= PLLD_MISC0_DEFAULT_VALUE;
+	/* set IDDQ, enable lock detect, disable SDM */
+	writel_relaxed(val, clk_base + plld->params->ext_misc_reg[0]);
+	writel_relaxed(PLLD_MISC1_DEFAULT_VALUE, clk_base +
+			plld->params->ext_misc_reg[1]);
+	udelay(1);
+}
+
+/*
+ * PLLD2, PLLDP
+ * PLL with fractional SDM and Spread Spectrum (SDM is a must if SSC is used).
+ */
+static void plldss_defaults(const char *pll_name, struct tegra_clk_pll *plldss,
+		u32 misc0_val, u32 misc1_val, u32 misc2_val, u32 misc3_val)
+{
+	u32 default_val;
+	u32 val = readl_relaxed(clk_base + plldss->params->base_reg);
+
+	plldss->params->defaults_set = true;
+
+	if (val & PLL_ENABLE) {
+		pr_warn("%s already enabled. Postponing set full defaults\n",
+			 pll_name);
+
+		/*
+		 * PLL is ON: check if defaults already set, then set those
+		 * that can be updated in flight.
+		 */
+		if (val & PLLDSS_BASE_IDDQ) {
+			pr_warn("plldss boot enabled with IDDQ set\n");
+			plldss->params->defaults_set = false;
+		}
+
+		/* ignore lock enable */
+		default_val = misc0_val;
+		_pll_misc_chk_default(clk_base, plldss->params, 0, default_val,
+				     PLLDSS_MISC0_WRITE_MASK &
+				     (~PLLDSS_MISC0_LOCK_ENABLE));
+
+		/*
+		 * If SSC is used, check all settings, otherwise just confirm
+		 * that SSC is not used on boot as well. Do nothing when using
+		 * this function for PLLC4 that has only MISC0.
+		 */
+		if (plldss->params->ssc_ctrl_en_mask) {
+			default_val = misc1_val;
+			_pll_misc_chk_default(clk_base, plldss->params, 1,
+				default_val, PLLDSS_MISC1_CFG_WRITE_MASK);
+			default_val = misc2_val;
+			_pll_misc_chk_default(clk_base, plldss->params, 2,
+				default_val, PLLDSS_MISC2_CTRL1_WRITE_MASK);
+			default_val = misc3_val;
+			_pll_misc_chk_default(clk_base, plldss->params, 3,
+				default_val, PLLDSS_MISC3_CTRL2_WRITE_MASK);
+		} else if (plldss->params->ext_misc_reg[1]) {
+			default_val = misc1_val;
+			_pll_misc_chk_default(clk_base, plldss->params, 1,
+				default_val, PLLDSS_MISC1_CFG_WRITE_MASK &
+				(~PLLDSS_MISC1_CFG_EN_SDM));
+		}
+
+		/* Enable lock detect */
+		if (val & PLLDSS_BASE_LOCK_OVERRIDE) {
+			val &= ~PLLDSS_BASE_LOCK_OVERRIDE;
+			writel_relaxed(val, clk_base +
+					plldss->params->base_reg);
+		}
+
+		val = readl_relaxed(clk_base + plldss->params->ext_misc_reg[0]);
+		val &= ~PLLDSS_MISC0_LOCK_ENABLE;
+		val |= misc0_val & PLLDSS_MISC0_LOCK_ENABLE;
+		writel_relaxed(val, clk_base + plldss->params->ext_misc_reg[0]);
+		udelay(1);
+
+		return;
+	}
+
+	/* set IDDQ, enable lock detect, configure SDM/SSC  */
+	val |= PLLDSS_BASE_IDDQ;
+	val &= ~PLLDSS_BASE_LOCK_OVERRIDE;
+	writel_relaxed(val, clk_base + plldss->params->base_reg);
+
+	/* When using this function for PLLC4 exit here */
+	if (!plldss->params->ext_misc_reg[1]) {
+		writel_relaxed(misc0_val, clk_base +
+				plldss->params->ext_misc_reg[0]);
+		udelay(1);
+		return;
+	}
+
+	writel_relaxed(misc0_val, clk_base +
+			plldss->params->ext_misc_reg[0]);
+	/* if SSC used set by 1st enable */
+	writel_relaxed(misc1_val & (~PLLDSS_MISC1_CFG_EN_SSC),
+			clk_base + plldss->params->ext_misc_reg[1]);
+	writel_relaxed(misc2_val, clk_base + plldss->params->ext_misc_reg[2]);
+	writel_relaxed(misc3_val, clk_base + plldss->params->ext_misc_reg[3]);
+	udelay(1);
+}
+
+void tegra210_plld2_set_defaults(struct tegra_clk_pll *plld2)
+{
+	plldss_defaults("PLL_D2", plld2, PLLD2_MISC0_DEFAULT_VALUE,
+			PLLD2_MISC1_CFG_DEFAULT_VALUE,
+			PLLD2_MISC2_CTRL1_DEFAULT_VALUE,
+			PLLD2_MISC3_CTRL2_DEFAULT_VALUE);
+}
+
+void tegra210_plldp_set_defaults(struct tegra_clk_pll *plldp)
+{
+	plldss_defaults("PLL_DP", plldp, PLLDP_MISC0_DEFAULT_VALUE,
+			PLLDP_MISC1_CFG_DEFAULT_VALUE,
+			PLLDP_MISC2_CTRL1_DEFAULT_VALUE,
+			PLLDP_MISC3_CTRL2_DEFAULT_VALUE);
+}
+
+/*
+ * PLLC4
+ * Base and misc0 layout is the same as PLLD2/PLLDP, but no SDM/SSC support.
+ * VCO is exposed to the clock tree via fixed 1/3 and 1/5 dividers.
+ */
+void tegra210_pllc4_set_defaults(struct tegra_clk_pll *pllc4)
+{
+	plldss_defaults("PLL_C4", pllc4, PLLC4_MISC0_DEFAULT_VALUE, 0, 0, 0);
+}
+
+/*
+ * PLLRE
+ * VCO is exposed to the clock tree directly along with post-divider output
+ */
+void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre)
+{
+	u32 mask;
+	u32 val = readl_relaxed(clk_base + pllre->params->base_reg);
+
+	pllre->params->defaults_set = true;
+
+	if (val & PLL_ENABLE) {
+		pr_warn("PLL_RE already enabled. Postponing set full defaults\n");
+
+		/*
+		 * PLL is ON: check if defaults already set, then set those
+		 * that can be updated in flight.
+		 */
+		val &= PLLRE_BASE_DEFAULT_MASK;
+		if (val != PLLRE_BASE_DEFAULT_VALUE) {
+			pr_warn("pllre boot base 0x%x : expected 0x%x\n",
+				val, PLLRE_BASE_DEFAULT_VALUE);
+			pr_warn("(comparison mask = 0x%x)\n",
+				PLLRE_BASE_DEFAULT_MASK);
+			pllre->params->defaults_set = false;
+		}
+
+		/* Ignore lock enable */
+		val = PLLRE_MISC0_DEFAULT_VALUE & (~PLLRE_MISC0_IDDQ);
+		mask = PLLRE_MISC0_LOCK_ENABLE | PLLRE_MISC0_LOCK_OVERRIDE;
+		_pll_misc_chk_default(clk_base, pllre->params, 0, val,
+				~mask & PLLRE_MISC0_WRITE_MASK);
+
+		/* Enable lock detect */
+		val = readl_relaxed(clk_base + pllre->params->ext_misc_reg[0]);
+		val &= ~mask;
+		val |= PLLRE_MISC0_DEFAULT_VALUE & mask;
+		writel_relaxed(val, clk_base + pllre->params->ext_misc_reg[0]);
+		udelay(1);
+
+		return;
+	}
+
+	/* set IDDQ, enable lock detect */
+	val &= ~PLLRE_BASE_DEFAULT_MASK;
+	val |= PLLRE_BASE_DEFAULT_VALUE & PLLRE_BASE_DEFAULT_MASK;
+	writel_relaxed(val, clk_base + pllre->params->base_reg);
+	writel_relaxed(PLLRE_MISC0_DEFAULT_VALUE,
+			clk_base + pllre->params->ext_misc_reg[0]);
+	udelay(1);
+}
+
+static void pllx_get_dyn_steps(struct clk_hw *hw, u32 *step_a, u32 *step_b)
+{
+	unsigned long input_rate;
+
+	if (!IS_ERR_OR_NULL(hw->clk)) {
+		input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
+		/* cf rate */
+		input_rate /= tegra_pll_get_fixed_mdiv(hw, input_rate);
+	} else {
+		input_rate = 38400000;
+	}
+
+	switch (input_rate) {
+	case 12000000:
+	case 12800000:
+	case 13000000:
+		*step_a = 0x2B;
+		*step_b = 0x0B;
+		return;
+	case 19200000:
+		*step_a = 0x12;
+		*step_b = 0x08;
+		return;
+	case 38400000:
+		*step_a = 0x04;
+		*step_b = 0x05;
+		return;
+	default:
+		pr_err("%s: Unexpected reference rate %lu\n",
+			__func__, input_rate);
+		BUG();
+	}
+}
+
+static void pllx_check_defaults(struct tegra_clk_pll *pll)
+{
+	u32 default_val;
+
+	default_val = PLLX_MISC0_DEFAULT_VALUE;
+	/* ignore lock enable */
+	_pll_misc_chk_default(clk_base, pll->params, 0, default_val,
+			PLLX_MISC0_WRITE_MASK & (~PLLX_MISC0_LOCK_ENABLE));
+
+	default_val = PLLX_MISC1_DEFAULT_VALUE;
+	_pll_misc_chk_default(clk_base, pll->params, 1, default_val,
+			PLLX_MISC1_WRITE_MASK);
+
+	/* ignore all but control bit */
+	default_val = PLLX_MISC2_DEFAULT_VALUE;
+	_pll_misc_chk_default(clk_base, pll->params, 2,
+			default_val, PLLX_MISC2_EN_DYNRAMP);
+
+	default_val = PLLX_MISC3_DEFAULT_VALUE & (~PLLX_MISC3_IDDQ);
+	_pll_misc_chk_default(clk_base, pll->params, 3, default_val,
+			PLLX_MISC3_WRITE_MASK);
+
+	default_val = PLLX_MISC4_DEFAULT_VALUE;
+	_pll_misc_chk_default(clk_base, pll->params, 4, default_val,
+			PLLX_MISC4_WRITE_MASK);
+
+	default_val = PLLX_MISC5_DEFAULT_VALUE;
+	_pll_misc_chk_default(clk_base, pll->params, 5, default_val,
+			PLLX_MISC5_WRITE_MASK);
+}
+
+void tegra210_pllx_set_defaults(struct tegra_clk_pll *pllx)
+{
+	u32 val;
+	u32 step_a, step_b;
+
+	pllx->params->defaults_set = true;
+
+	/* Get ready dyn ramp state machine settings */
+	pllx_get_dyn_steps(&pllx->hw, &step_a, &step_b);
+	val = PLLX_MISC2_DEFAULT_VALUE & (~PLLX_MISC2_DYNRAMP_STEPA_MASK) &
+		(~PLLX_MISC2_DYNRAMP_STEPB_MASK);
+	val |= step_a << PLLX_MISC2_DYNRAMP_STEPA_SHIFT;
+	val |= step_b << PLLX_MISC2_DYNRAMP_STEPB_SHIFT;
+
+	if (readl_relaxed(clk_base + pllx->params->base_reg) & PLL_ENABLE) {
+		pr_warn("PLL_X already enabled. Postponing set full defaults\n");
+
+		/*
+		 * PLL is ON: check if defaults already set, then set those
+		 * that can be updated in flight.
+		 */
+		pllx_check_defaults(pllx);
+
+		/* Configure dyn ramp, disable lock override */
+		writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
+
+		/* Enable lock detect */
+		val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[0]);
+		val &= ~PLLX_MISC0_LOCK_ENABLE;
+		val |= PLLX_MISC0_DEFAULT_VALUE & PLLX_MISC0_LOCK_ENABLE;
+		writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[0]);
+		udelay(1);
+
+		return;
+	}
+
+	/* Enable lock detect and CPU output */
+	writel_relaxed(PLLX_MISC0_DEFAULT_VALUE, clk_base +
+			pllx->params->ext_misc_reg[0]);
+
+	/* Setup */
+	writel_relaxed(PLLX_MISC1_DEFAULT_VALUE, clk_base +
+			pllx->params->ext_misc_reg[1]);
+
+	/* Configure dyn ramp state machine, disable lock override */
+	writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
+
+	/* Set IDDQ */
+	writel_relaxed(PLLX_MISC3_DEFAULT_VALUE, clk_base +
+			pllx->params->ext_misc_reg[3]);
+
+	/* Disable SDM */
+	writel_relaxed(PLLX_MISC4_DEFAULT_VALUE, clk_base +
+			pllx->params->ext_misc_reg[4]);
+	writel_relaxed(PLLX_MISC5_DEFAULT_VALUE, clk_base +
+			pllx->params->ext_misc_reg[5]);
+	udelay(1);
+}
+
+/* PLLMB */
+void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb)
+{
+	u32 mask, val = readl_relaxed(clk_base + pllmb->params->base_reg);
+
+	pllmb->params->defaults_set = true;
+
+	if (val & PLL_ENABLE) {
+		pr_warn("PLL_MB already enabled. Postponing set full defaults\n");
+
+		/*
+		 * PLL is ON: check if defaults already set, then set those
+		 * that can be updated in flight.
+		 */
+		val = PLLMB_MISC0_DEFAULT_VALUE & (~PLLMB_MISC0_IDDQ);
+		mask = PLLMB_MISC0_LOCK_ENABLE | PLLMB_MISC0_LOCK_OVERRIDE;
+		_pll_misc_chk_default(clk_base, pllmb->params, 0, val,
+				~mask & PLLMB_MISC0_WRITE_MASK);
+
+		/* Enable lock detect */
+		val = readl_relaxed(clk_base + pllmb->params->ext_misc_reg[0]);
+		val &= ~mask;
+		val |= PLLMB_MISC0_DEFAULT_VALUE & mask;
+		writel_relaxed(val, clk_base + pllmb->params->ext_misc_reg[0]);
+		udelay(1);
+
+		return;
+	}
+
+	/* set IDDQ, enable lock detect */
+	writel_relaxed(PLLMB_MISC0_DEFAULT_VALUE,
+			clk_base + pllmb->params->ext_misc_reg[0]);
+	udelay(1);
+}
+
+/*
+ * PLLP
+ * VCO is exposed to the clock tree directly along with post-divider output.
+ * Both VCO and post-divider output rates are fixed at 408MHz and 204MHz,
+ * respectively.
+ */
+static void pllp_check_defaults(struct tegra_clk_pll *pll, bool enabled)
+{
+	u32 val, mask;
+
+	/* Ignore lock enable (will be set), make sure not in IDDQ if enabled */
+	val = PLLP_MISC0_DEFAULT_VALUE & (~PLLP_MISC0_IDDQ);
+	mask = PLLP_MISC0_LOCK_ENABLE | PLLP_MISC0_LOCK_OVERRIDE;
+	if (!enabled)
+		mask |= PLLP_MISC0_IDDQ;
+	_pll_misc_chk_default(clk_base, pll->params, 0, val,
+			~mask & PLLP_MISC0_WRITE_MASK);
+
+	/* Ignore branch controls */
+	val = PLLP_MISC1_DEFAULT_VALUE;
+	mask = PLLP_MISC1_HSIO_EN | PLLP_MISC1_XUSB_EN;
+	_pll_misc_chk_default(clk_base, pll->params, 1, val,
+			~mask & PLLP_MISC1_WRITE_MASK);
+}
+
+void tegra210_pllp_set_defaults(struct tegra_clk_pll *pllp)
+{
+	u32 mask;
+	u32 val = readl_relaxed(clk_base + pllp->params->base_reg);
+
+	pllp->params->defaults_set = true;
+
+	if (val & PLL_ENABLE) {
+		pr_warn("PLL_P already enabled. Postponing set full defaults\n");
+
+		/*
+		 * PLL is ON: check if defaults already set, then set those
+		 * that can be updated in flight.
+		 */
+		pllp_check_defaults(pllp, true);
+
+		/* Enable lock detect */
+		val = readl_relaxed(clk_base + pllp->params->ext_misc_reg[0]);
+		mask = PLLP_MISC0_LOCK_ENABLE | PLLP_MISC0_LOCK_OVERRIDE;
+		val &= ~mask;
+		val |= PLLP_MISC0_DEFAULT_VALUE & mask;
+		writel_relaxed(val, clk_base + pllp->params->ext_misc_reg[0]);
+		udelay(1);
+
+		return;
+	}
+
+	/* set IDDQ, enable lock detect */
+	writel_relaxed(PLLP_MISC0_DEFAULT_VALUE,
+			clk_base + pllp->params->ext_misc_reg[0]);
+
+	/* Preserve branch control */
+	val = readl_relaxed(clk_base + pllp->params->ext_misc_reg[1]);
+	mask = PLLP_MISC1_HSIO_EN | PLLP_MISC1_XUSB_EN;
+	val &= mask;
+	val |= ~mask & PLLP_MISC1_DEFAULT_VALUE;
+	writel_relaxed(val, clk_base + pllp->params->ext_misc_reg[1]);
+	udelay(1);
+}
+
+/*
+ * PLLU
+ * VCO is exposed to the clock tree directly along with post-divider output.
+ * Both VCO and post-divider output rates are fixed at 480MHz and 240MHz,
+ * respectively.
+ */
+static void pllu_check_defaults(struct tegra_clk_pll *pll, bool hw_control)
+{
+	u32 val, mask;
+
+	/* Ignore lock enable (will be set) and IDDQ if under h/w control */
+	val = PLLU_MISC0_DEFAULT_VALUE & (~PLLU_MISC0_IDDQ);
+	mask = PLLU_MISC0_LOCK_ENABLE | (hw_control ? PLLU_MISC0_IDDQ : 0);
+	_pll_misc_chk_default(clk_base, pll->params, 0, val,
+			~mask & PLLU_MISC0_WRITE_MASK);
+
+	val = PLLU_MISC1_DEFAULT_VALUE;
+	mask = PLLU_MISC1_LOCK_OVERRIDE;
+	_pll_misc_chk_default(clk_base, pll->params, 1, val,
+			~mask & PLLU_MISC1_WRITE_MASK);
+}
+
+void tegra210_pllu_set_defaults(struct tegra_clk_pll *pllu)
+{
+	u32 val = readl_relaxed(clk_base + pllu->params->base_reg);
+
+	pllu->params->defaults_set = true;
+
+	if (val & PLL_ENABLE) {
+		pr_warn("PLL_U already enabled. Postponing set full defaults\n");
+
+		/*
+		 * PLL is ON: check if defaults already set, then set those
+		 * that can be updated in flight.
+		 */
+		pllu_check_defaults(pllu, false);
+
+		/* Enable lock detect */
+		val = readl_relaxed(clk_base + pllu->params->ext_misc_reg[0]);
+		val &= ~PLLU_MISC0_LOCK_ENABLE;
+		val |= PLLU_MISC0_DEFAULT_VALUE & PLLU_MISC0_LOCK_ENABLE;
+		writel_relaxed(val, clk_base + pllu->params->ext_misc_reg[0]);
+
+		val = readl_relaxed(clk_base + pllu->params->ext_misc_reg[1]);
+		val &= ~PLLU_MISC1_LOCK_OVERRIDE;
+		val |= PLLU_MISC1_DEFAULT_VALUE & PLLU_MISC1_LOCK_OVERRIDE;
+		writel_relaxed(val, clk_base + pllu->params->ext_misc_reg[1]);
+		udelay(1);
+
+		return;
+	}
+
+	/* set IDDQ, enable lock detect */
+	writel_relaxed(PLLU_MISC0_DEFAULT_VALUE,
+			clk_base + pllu->params->ext_misc_reg[0]);
+	writel_relaxed(PLLU_MISC1_DEFAULT_VALUE,
+			clk_base + pllu->params->ext_misc_reg[1]);
+	udelay(1);
+}
+
+#define mask(w) ((1 << (w)) - 1)
+#define divm_mask(p) mask(p->params->div_nmp->divm_width)
+#define divn_mask(p) mask(p->params->div_nmp->divn_width)
+#define divp_mask(p) (p->params->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK :\
+		      mask(p->params->div_nmp->divp_width))
+
+#define divm_shift(p) ((p)->params->div_nmp->divm_shift)
+#define divn_shift(p) ((p)->params->div_nmp->divn_shift)
+#define divp_shift(p) ((p)->params->div_nmp->divp_shift)
+
+#define divm_mask_shifted(p) (divm_mask(p) << divm_shift(p))
+#define divn_mask_shifted(p) (divn_mask(p) << divn_shift(p))
+#define divp_mask_shifted(p) (divp_mask(p) << divp_shift(p))
+
+#define PLL_LOCKDET_DELAY 2	/* Lock detection safety delays */
+static int tegra210_wait_for_mask(struct tegra_clk_pll *pll,
+				  u32 reg, u32 mask)
+{
+	int i;
+	u32 val = 0;
+
+	for (i = 0; i < pll->params->lock_delay / PLL_LOCKDET_DELAY + 1; i++) {
+		udelay(PLL_LOCKDET_DELAY);
+		val = readl_relaxed(clk_base + reg);
+		if ((val & mask) == mask) {
+			udelay(PLL_LOCKDET_DELAY);
+			return 0;
+		}
+	}
+	return -ETIMEDOUT;
+}
+
+static int tegra210_pllx_dyn_ramp(struct tegra_clk_pll *pllx,
+		struct tegra_clk_pll_freq_table *cfg)
+{
+	u32 val, base, ndiv_new_mask;
+
+	ndiv_new_mask = (divn_mask(pllx) >> pllx->params->div_nmp->divn_shift)
+			 << PLLX_MISC2_NDIV_NEW_SHIFT;
+
+	val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[2]);
+	val &= (~ndiv_new_mask);
+	val |= cfg->n << PLLX_MISC2_NDIV_NEW_SHIFT;
+	writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
+	udelay(1);
+
+	val = readl_relaxed(clk_base + pllx->params->ext_misc_reg[2]);
+	val |= PLLX_MISC2_EN_DYNRAMP;
+	writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
+	udelay(1);
+
+	tegra210_wait_for_mask(pllx, pllx->params->ext_misc_reg[2],
+			       PLLX_MISC2_DYNRAMP_DONE);
+
+	base = readl_relaxed(clk_base + pllx->params->base_reg) &
+		(~divn_mask_shifted(pllx));
+	base |= cfg->n << pllx->params->div_nmp->divn_shift;
+	writel_relaxed(base, clk_base + pllx->params->base_reg);
+	udelay(1);
+
+	val &= ~PLLX_MISC2_EN_DYNRAMP;
+	writel_relaxed(val, clk_base + pllx->params->ext_misc_reg[2]);
+	udelay(1);
+
+	pr_debug("%s: dynamic ramp to m = %u n = %u p = %u, Fout = %lu kHz\n",
+		 __clk_get_name(pllx->hw.clk), cfg->m, cfg->n, cfg->p,
+		 cfg->input_rate / cfg->m * cfg->n /
+		 pllx->params->pdiv_tohw[cfg->p].pdiv / 1000);
+
+	return 0;
+}
+
+/*
+ * Common configuration for PLLs with fixed input divider policy:
+ * - always set fixed M-value based on the reference rate
+ * - always set P-value value 1:1 for output rates above VCO minimum, and
+ *   choose minimum necessary P-value for output rates below VCO maximum
+ * - calculate N-value based on selected M and P
+ * - calculate SDM_DIN fractional part
+ */
+static int tegra210_pll_fixed_mdiv_cfg(struct clk_hw *hw,
+			       struct tegra_clk_pll_freq_table *cfg,
+			       unsigned long rate, unsigned long input_rate)
+{
+	struct tegra_clk_pll *pll = to_clk_pll(hw);
+	struct tegra_clk_pll_params *params = pll->params;
+	int p;
+	unsigned long cf, p_rate;
+	u32 pdiv;
+
+	if (!rate)
+		return -EINVAL;
+
+	if (!(params->flags & TEGRA_PLL_VCO_OUT)) {
+		p = DIV_ROUND_UP(params->vco_min, rate);
+		p = params->round_p_to_pdiv(p, &pdiv);
+	} else {
+		p = rate >= params->vco_min ? 1 : -EINVAL;
+	}
+
+	if (IS_ERR_VALUE(p))
+		return -EINVAL;
+
+	cfg->m = tegra_pll_get_fixed_mdiv(hw, input_rate);
+	cfg->p = p;
+
+	/* Store P as HW value, as that is what is expected */
+	cfg->p = tegra_pll_p_div_to_hw(pll, cfg->p);
+
+	p_rate = rate * p;
+	if (p_rate > params->vco_max)
+		p_rate = params->vco_max;
+	cf = input_rate / cfg->m;
+	cfg->n = p_rate / cf;
+
+	cfg->sdm_data = 0;
+	if (params->sdm_ctrl_reg) {
+		unsigned long rem = p_rate - cf * cfg->n;
+		/* If ssc is enabled SDM enabled as well, even for integer n */
+		if (rem || params->ssc_ctrl_reg) {
+			u64 s = rem * PLL_SDM_COEFF;
+
+			do_div(s, cf);
+			s -= PLL_SDM_COEFF / 2;
+			cfg->sdm_data = sdin_din_to_data(s);
+		}
+	}
+
+	cfg->input_rate = input_rate;
+	cfg->output_rate = rate;
+
+	return 0;
+}
+
+/*
+ * clk_pll_set_gain - set gain to m, n to calculate correct VCO rate
+ *
+ * @cfg: struct tegra_clk_pll_freq_table * cfg
+ *
+ * For Normal mode:
+ *     Fvco = Fref * NDIV / MDIV
+ *
+ * For fractional mode:
+ *     Fvco = Fref * (NDIV + 0.5 + SDM_DIN / PLL_SDM_COEFF) / MDIV
+ */
+static void tegra210_clk_pll_set_gain(struct tegra_clk_pll_freq_table *cfg)
+{
+	cfg->n = cfg->n * PLL_SDM_COEFF + PLL_SDM_COEFF/2 +
+			sdin_data_to_din(cfg->sdm_data);
+	cfg->m *= PLL_SDM_COEFF;
+}
+
+unsigned long tegra210_clk_adjust_vco_min(struct tegra_clk_pll_params *params,
+					  unsigned long parent_rate)
+{
+	unsigned long vco_min = params->vco_min;
+
+	params->vco_min += DIV_ROUND_UP(parent_rate, PLL_SDM_COEFF);
+	vco_min = min(vco_min, params->vco_min);
+
+	return vco_min;
+}
+
+static struct div_nmp pllx_nmp = {
+	.divm_shift = 0,
+	.divm_width = 8,
+	.divn_shift = 8,
+	.divn_width = 8,
+	.divp_shift = 20,
+	.divp_width = 5,
+};
+/*
+ * PLL post divider maps - two types: quasi-linear and exponential
+ * post divider.
+ */
+#define PLL_QLIN_PDIV_MAX	16
+static const struct pdiv_map pll_qlin_pdiv_to_hw[] = {
+	{ .pdiv =  1, .hw_val =  0 },
+	{ .pdiv =  2, .hw_val =  1 },
+	{ .pdiv =  3, .hw_val =  2 },
+	{ .pdiv =  4, .hw_val =  3 },
+	{ .pdiv =  5, .hw_val =  4 },
+	{ .pdiv =  6, .hw_val =  5 },
+	{ .pdiv =  8, .hw_val =  6 },
+	{ .pdiv =  9, .hw_val =  7 },
+	{ .pdiv = 10, .hw_val =  8 },
+	{ .pdiv = 12, .hw_val =  9 },
+	{ .pdiv = 15, .hw_val = 10 },
+	{ .pdiv = 16, .hw_val = 11 },
+	{ .pdiv = 18, .hw_val = 12 },
+	{ .pdiv = 20, .hw_val = 13 },
+	{ .pdiv = 24, .hw_val = 14 },
+	{ .pdiv = 30, .hw_val = 15 },
+	{ .pdiv = 32, .hw_val = 16 },
+};
+
+static u32 pll_qlin_p_to_pdiv(u32 p, u32 *pdiv)
+{
+	int i;
+
+	if (p) {
+		for (i = 0; i <= PLL_QLIN_PDIV_MAX; i++) {
+			if (p <= pll_qlin_pdiv_to_hw[i].pdiv) {
+				if (pdiv)
+					*pdiv = i;
+				return pll_qlin_pdiv_to_hw[i].pdiv;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+#define PLL_EXPO_PDIV_MAX	7
+static const struct pdiv_map pll_expo_pdiv_to_hw[] = {
+	{ .pdiv =   1, .hw_val = 0 },
+	{ .pdiv =   2, .hw_val = 1 },
+	{ .pdiv =   4, .hw_val = 2 },
+	{ .pdiv =   8, .hw_val = 3 },
+	{ .pdiv =  16, .hw_val = 4 },
+	{ .pdiv =  32, .hw_val = 5 },
+	{ .pdiv =  64, .hw_val = 6 },
+	{ .pdiv = 128, .hw_val = 7 },
+};
+
+static u32 pll_expo_p_to_pdiv(u32 p, u32 *pdiv)
+{
+	if (p) {
+		u32 i = fls(p);
+
+		if (i == ffs(p))
+			i--;
+
+		if (i <= PLL_EXPO_PDIV_MAX) {
+			if (pdiv)
+				*pdiv = i;
+			return 1 << i;
+		}
+	}
+	return -EINVAL;
+}
+
+static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
+	/* 1 GHz */
+	{ 12000000, 1000000000, 166, 1, 1, 0 }, /* actual: 996.0 MHz */
+	{ 13000000, 1000000000, 153, 1, 1, 0 }, /* actual: 994.0 MHz */
+	{ 38400000, 1000000000, 156, 3, 1, 0 }, /* actual: 998.4 MHz */
+	{        0,          0,   0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_params pll_x_params = {
+	.input_min = 12000000,
+	.input_max = 800000000,
+	.cf_min = 12000000,
+	.cf_max = 38400000,
+	.vco_min = 1350000000,
+	.vco_max = 3000000000UL,
+	.base_reg = PLLX_BASE,
+	.misc_reg = PLLX_MISC0,
+	.lock_mask = PLL_BASE_LOCK,
+	.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+	.lock_delay = 300,
+	.ext_misc_reg[0] = PLLX_MISC0,
+	.ext_misc_reg[1] = PLLX_MISC1,
+	.ext_misc_reg[2] = PLLX_MISC2,
+	.ext_misc_reg[3] = PLLX_MISC3,
+	.ext_misc_reg[4] = PLLX_MISC4,
+	.ext_misc_reg[5] = PLLX_MISC5,
+	.iddq_reg = PLLX_MISC3,
+	.iddq_bit_idx = PLLXP_IDDQ_BIT,
+	.max_p = PLL_QLIN_PDIV_MAX,
+	.mdiv_default = 2,
+	.dyn_ramp_reg = PLLX_MISC2,
+	.stepa_shift = 16,
+	.stepb_shift = 24,
+	.round_p_to_pdiv = pll_qlin_p_to_pdiv,
+	.pdiv_tohw = pll_qlin_pdiv_to_hw,
+	.div_nmp = &pllx_nmp,
+	.freq_table = pll_x_freq_table,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+	.dyn_ramp = tegra210_pllx_dyn_ramp,
+	.set_defaults = tegra210_pllx_set_defaults,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct div_nmp pllc_nmp = {
+	.divm_shift = 0,
+	.divm_width = 8,
+	.divn_shift = 10,
+	.divn_width = 8,
+	.divp_shift = 20,
+	.divp_width = 5,
+};
+
+static struct tegra_clk_pll_freq_table pll_cx_freq_table[] = {
+	{ 12000000, 510000000, 85, 1, 1, 0 },
+	{ 13000000, 510000000, 78, 1, 1, 0 }, /* actual: 507.0 MHz */
+	{ 38400000, 510000000, 79, 3, 1, 0 }, /* actual: 505.6 MHz */
+	{        0,         0,  0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_params pll_c_params = {
+	.input_min = 12000000,
+	.input_max = 700000000,
+	.cf_min = 12000000,
+	.cf_max = 50000000,
+	.vco_min = 600000000,
+	.vco_max = 1200000000,
+	.base_reg = PLLC_BASE,
+	.misc_reg = PLLC_MISC0,
+	.lock_mask = PLL_BASE_LOCK,
+	.lock_delay = 300,
+	.iddq_reg = PLLC_MISC1,
+	.iddq_bit_idx = PLLCX_IDDQ_BIT,
+	.reset_reg = PLLC_MISC0,
+	.reset_bit_idx = PLLCX_RESET_BIT,
+	.max_p = PLL_QLIN_PDIV_MAX,
+	.ext_misc_reg[0] = PLLC_MISC0,
+	.ext_misc_reg[1] = PLLC_MISC1,
+	.ext_misc_reg[2] = PLLC_MISC2,
+	.ext_misc_reg[3] = PLLC_MISC3,
+	.round_p_to_pdiv = pll_qlin_p_to_pdiv,
+	.pdiv_tohw = pll_qlin_pdiv_to_hw,
+	.mdiv_default = 3,
+	.div_nmp = &pllc_nmp,
+	.freq_table = pll_cx_freq_table,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+	.set_defaults = _pllc_set_defaults,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct div_nmp pllcx_nmp = {
+	.divm_shift = 0,
+	.divm_width = 8,
+	.divn_shift = 10,
+	.divn_width = 8,
+	.divp_shift = 20,
+	.divp_width = 5,
+};
+
+static struct tegra_clk_pll_params pll_c2_params = {
+	.input_min = 12000000,
+	.input_max = 700000000,
+	.cf_min = 12000000,
+	.cf_max = 50000000,
+	.vco_min = 600000000,
+	.vco_max = 1200000000,
+	.base_reg = PLLC2_BASE,
+	.misc_reg = PLLC2_MISC0,
+	.iddq_reg = PLLC2_MISC1,
+	.iddq_bit_idx = PLLCX_IDDQ_BIT,
+	.reset_reg = PLLC2_MISC0,
+	.reset_bit_idx = PLLCX_RESET_BIT,
+	.lock_mask = PLLCX_BASE_LOCK,
+	.lock_delay = 300,
+	.round_p_to_pdiv = pll_qlin_p_to_pdiv,
+	.pdiv_tohw = pll_qlin_pdiv_to_hw,
+	.mdiv_default = 3,
+	.div_nmp = &pllcx_nmp,
+	.max_p = PLL_QLIN_PDIV_MAX,
+	.ext_misc_reg[0] = PLLC2_MISC0,
+	.ext_misc_reg[1] = PLLC2_MISC1,
+	.ext_misc_reg[2] = PLLC2_MISC2,
+	.ext_misc_reg[3] = PLLC2_MISC3,
+	.freq_table = pll_cx_freq_table,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+	.set_defaults = _pllc2_set_defaults,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct tegra_clk_pll_params pll_c3_params = {
+	.input_min = 12000000,
+	.input_max = 700000000,
+	.cf_min = 12000000,
+	.cf_max = 50000000,
+	.vco_min = 600000000,
+	.vco_max = 1200000000,
+	.base_reg = PLLC3_BASE,
+	.misc_reg = PLLC3_MISC0,
+	.lock_mask = PLLCX_BASE_LOCK,
+	.lock_delay = 300,
+	.iddq_reg = PLLC3_MISC1,
+	.iddq_bit_idx = PLLCX_IDDQ_BIT,
+	.reset_reg = PLLC3_MISC0,
+	.reset_bit_idx = PLLCX_RESET_BIT,
+	.round_p_to_pdiv = pll_qlin_p_to_pdiv,
+	.pdiv_tohw = pll_qlin_pdiv_to_hw,
+	.mdiv_default = 3,
+	.div_nmp = &pllcx_nmp,
+	.max_p = PLL_QLIN_PDIV_MAX,
+	.ext_misc_reg[0] = PLLC3_MISC0,
+	.ext_misc_reg[1] = PLLC3_MISC1,
+	.ext_misc_reg[2] = PLLC3_MISC2,
+	.ext_misc_reg[3] = PLLC3_MISC3,
+	.freq_table = pll_cx_freq_table,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+	.set_defaults = _pllc3_set_defaults,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct div_nmp pllss_nmp = {
+	.divm_shift = 0,
+	.divm_width = 8,
+	.divn_shift = 8,
+	.divn_width = 8,
+	.divp_shift = 19,
+	.divp_width = 5,
+};
+
+static struct tegra_clk_pll_freq_table pll_c4_vco_freq_table[] = {
+	{ 12000000, 600000000, 50, 1, 0, 0 },
+	{ 13000000, 600000000, 46, 1, 0, 0 }, /* actual: 598.0 MHz */
+	{ 38400000, 600000000, 62, 4, 0, 0 }, /* actual: 595.2 MHz */
+	{        0,         0,  0, 0, 0, 0 },
+};
+
+static const struct clk_div_table pll_vco_post_div_table[] = {
+	{ .val =  0, .div =  1 },
+	{ .val =  1, .div =  2 },
+	{ .val =  2, .div =  3 },
+	{ .val =  3, .div =  4 },
+	{ .val =  4, .div =  5 },
+	{ .val =  5, .div =  6 },
+	{ .val =  6, .div =  8 },
+	{ .val =  7, .div = 10 },
+	{ .val =  8, .div = 12 },
+	{ .val =  9, .div = 16 },
+	{ .val = 10, .div = 12 },
+	{ .val = 11, .div = 16 },
+	{ .val = 12, .div = 20 },
+	{ .val = 13, .div = 24 },
+	{ .val = 14, .div = 32 },
+	{ .val =  0, .div =  0 },
+};
+
+static struct tegra_clk_pll_params pll_c4_vco_params = {
+	.input_min = 9600000,
+	.input_max = 800000000,
+	.cf_min = 9600000,
+	.cf_max = 19200000,
+	.vco_min = 500000000,
+	.vco_max = 1080000000,
+	.base_reg = PLLC4_BASE,
+	.misc_reg = PLLC4_MISC0,
+	.lock_mask = PLL_BASE_LOCK,
+	.lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE,
+	.lock_delay = 300,
+	.max_p = PLL_QLIN_PDIV_MAX,
+	.ext_misc_reg[0] = PLLC4_MISC0,
+	.iddq_reg = PLLC4_BASE,
+	.iddq_bit_idx = PLLSS_IDDQ_BIT,
+	.round_p_to_pdiv = pll_qlin_p_to_pdiv,
+	.pdiv_tohw = pll_qlin_pdiv_to_hw,
+	.mdiv_default = 3,
+	.div_nmp = &pllss_nmp,
+	.freq_table = pll_c4_vco_freq_table,
+	.set_defaults = tegra210_pllc4_set_defaults,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
+		 TEGRA_PLL_VCO_OUT,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
+	{ 12000000,  800000000,  66, 1, 0, 0 }, /* actual: 792.0 MHz */
+	{ 13000000,  800000000,  61, 1, 0, 0 }, /* actual: 793.0 MHz */
+	{ 38400000,  297600000,  93, 4, 2, 0 },
+	{ 38400000,  400000000, 125, 4, 2, 0 },
+	{ 38400000,  532800000, 111, 4, 1, 0 },
+	{ 38400000,  665600000, 104, 3, 1, 0 },
+	{ 38400000,  800000000, 125, 3, 1, 0 },
+	{ 38400000,  931200000,  97, 4, 0, 0 },
+	{ 38400000, 1065600000, 111, 4, 0, 0 },
+	{ 38400000, 1200000000, 125, 4, 0, 0 },
+	{ 38400000, 1331200000, 104, 3, 0, 0 },
+	{ 38400000, 1459200000,  76, 2, 0, 0 },
+	{ 38400000, 1600000000, 125, 3, 0, 0 },
+	{        0,          0,   0, 0, 0, 0 },
+};
+
+static struct div_nmp pllm_nmp = {
+	.divm_shift = 0,
+	.divm_width = 8,
+	.override_divm_shift = 0,
+	.divn_shift = 8,
+	.divn_width = 8,
+	.override_divn_shift = 8,
+	.divp_shift = 20,
+	.divp_width = 5,
+	.override_divp_shift = 27,
+};
+
+static struct tegra_clk_pll_params pll_m_params = {
+	.input_min = 9600000,
+	.input_max = 500000000,
+	.cf_min = 9600000,
+	.cf_max = 19200000,
+	.vco_min = 800000000,
+	.vco_max = 1866000000,
+	.base_reg = PLLM_BASE,
+	.misc_reg = PLLM_MISC1,
+	.lock_mask = PLL_BASE_LOCK,
+	.lock_enable_bit_idx = PLLM_MISC_LOCK_ENABLE,
+	.lock_delay = 300,
+	.iddq_reg = PLLM_MISC0,
+	.iddq_bit_idx = PLLM_IDDQ_BIT,
+	.max_p = PLL_QLIN_PDIV_MAX,
+	.ext_misc_reg[0] = PLLM_MISC0,
+	.ext_misc_reg[0] = PLLM_MISC1,
+	.round_p_to_pdiv = pll_qlin_p_to_pdiv,
+	.pdiv_tohw = pll_qlin_pdiv_to_hw,
+	.div_nmp = &pllm_nmp,
+	.pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
+	.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
+	.freq_table = pll_m_freq_table,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct tegra_clk_pll_params pll_mb_params = {
+	.input_min = 9600000,
+	.input_max = 500000000,
+	.cf_min = 9600000,
+	.cf_max = 19200000,
+	.vco_min = 800000000,
+	.vco_max = 1866000000,
+	.base_reg = PLLMB_BASE,
+	.misc_reg = PLLMB_MISC0,
+	.lock_mask = PLL_BASE_LOCK,
+	.lock_enable_bit_idx = PLLMB_MISC_LOCK_ENABLE,
+	.lock_delay = 300,
+	.iddq_reg = PLLMB_MISC0,
+	.iddq_bit_idx = PLLMB_IDDQ_BIT,
+	.max_p = PLL_QLIN_PDIV_MAX,
+	.ext_misc_reg[0] = PLLMB_MISC0,
+	.round_p_to_pdiv = pll_qlin_p_to_pdiv,
+	.pdiv_tohw = pll_qlin_pdiv_to_hw,
+	.div_nmp = &pllm_nmp,
+	.freq_table = pll_m_freq_table,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+	.set_defaults = tegra210_pllmb_set_defaults,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+
+static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
+	/* PLLE special case: use cpcon field to store cml divider value */
+	{ 672000000, 100000000, 125, 42, 0, 13 },
+	{ 624000000, 100000000, 125, 39, 0, 13 },
+	{ 336000000, 100000000, 125, 21, 0, 13 },
+	{ 312000000, 100000000, 200, 26, 0, 14 },
+	{  38400000, 100000000, 125,  2, 0, 14 },
+	{  12000000, 100000000, 200,  1, 0, 14 },
+	{         0,         0,   0,  0, 0,  0 },
+};
+
+static struct div_nmp plle_nmp = {
+	.divm_shift = 0,
+	.divm_width = 8,
+	.divn_shift = 8,
+	.divn_width = 8,
+	.divp_shift = 24,
+	.divp_width = 5,
+};
+
+static struct tegra_clk_pll_params pll_e_params = {
+	.input_min = 12000000,
+	.input_max = 800000000,
+	.cf_min = 12000000,
+	.cf_max = 38400000,
+	.vco_min = 1600000000,
+	.vco_max = 2500000000U,
+	.base_reg = PLLE_BASE,
+	.misc_reg = PLLE_MISC0,
+	.aux_reg = PLLE_AUX,
+	.lock_mask = PLLE_MISC_LOCK,
+	.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
+	.lock_delay = 300,
+	.div_nmp = &plle_nmp,
+	.freq_table = pll_e_freq_table,
+	.flags = TEGRA_PLL_FIXED | TEGRA_PLL_LOCK_MISC | TEGRA_PLL_USE_LOCK |
+		 TEGRA_PLL_HAS_LOCK_ENABLE,
+	.fixed_rate = 100000000,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct tegra_clk_pll_freq_table pll_re_vco_freq_table[] = {
+	{ 12000000, 672000000, 56, 1, 0, 0 },
+	{ 13000000, 672000000, 51, 1, 0, 0 }, /* actual: 663.0 MHz */
+	{ 38400000, 672000000, 70, 4, 0, 0 },
+	{        0,         0,  0, 0, 0, 0 },
+};
+
+static struct div_nmp pllre_nmp = {
+	.divm_shift = 0,
+	.divm_width = 8,
+	.divn_shift = 8,
+	.divn_width = 8,
+	.divp_shift = 16,
+	.divp_width = 5,
+};
+
+static struct tegra_clk_pll_params pll_re_vco_params = {
+	.input_min = 9600000,
+	.input_max = 800000000,
+	.cf_min = 9600000,
+	.cf_max = 19200000,
+	.vco_min = 350000000,
+	.vco_max = 700000000,
+	.base_reg = PLLRE_BASE,
+	.misc_reg = PLLRE_MISC0,
+	.lock_mask = PLLRE_MISC_LOCK,
+	.lock_enable_bit_idx = PLLRE_MISC_LOCK_ENABLE,
+	.lock_delay = 300,
+	.max_p = PLL_QLIN_PDIV_MAX,
+	.ext_misc_reg[0] = PLLRE_MISC0,
+	.iddq_reg = PLLRE_MISC0,
+	.iddq_bit_idx = PLLRE_IDDQ_BIT,
+	.round_p_to_pdiv = pll_qlin_p_to_pdiv,
+	.pdiv_tohw = pll_qlin_pdiv_to_hw,
+	.div_nmp = &pllre_nmp,
+	.freq_table = pll_re_vco_freq_table,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_LOCK_MISC |
+		 TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_VCO_OUT,
+	.set_defaults = tegra210_pllre_set_defaults,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct div_nmp pllp_nmp = {
+	.divm_shift = 0,
+	.divm_width = 8,
+	.divn_shift = 10,
+	.divn_width = 8,
+	.divp_shift = 20,
+	.divp_width = 5,
+};
+
+static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
+	{ 12000000, 408000000, 34, 1, 0, 0 },
+	{ 38400000, 408000000, 85, 8, 0, 0 }, /* cf = 4.8MHz, allowed exception */
+	{        0,         0,  0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_params pll_p_params = {
+	.input_min = 9600000,
+	.input_max = 800000000,
+	.cf_min = 9600000,
+	.cf_max = 19200000,
+	.vco_min = 350000000,
+	.vco_max = 700000000,
+	.base_reg = PLLP_BASE,
+	.misc_reg = PLLP_MISC0,
+	.lock_mask = PLL_BASE_LOCK,
+	.lock_enable_bit_idx = PLLP_MISC_LOCK_ENABLE,
+	.lock_delay = 300,
+	.iddq_reg = PLLP_MISC0,
+	.iddq_bit_idx = PLLXP_IDDQ_BIT,
+	.ext_misc_reg[0] = PLLP_MISC0,
+	.ext_misc_reg[1] = PLLP_MISC1,
+	.div_nmp = &pllp_nmp,
+	.freq_table = pll_p_freq_table,
+	.fixed_rate = 408000000,
+	.flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK |
+		 TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_VCO_OUT,
+	.set_defaults = tegra210_pllp_set_defaults,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct tegra_clk_pll_params pll_a1_params = {
+	.input_min = 12000000,
+	.input_max = 700000000,
+	.cf_min = 12000000,
+	.cf_max = 50000000,
+	.vco_min = 600000000,
+	.vco_max = 1200000000,
+	.base_reg = PLLA1_BASE,
+	.misc_reg = PLLA1_MISC0,
+	.lock_mask = PLLCX_BASE_LOCK,
+	.lock_delay = 300,
+	.iddq_reg = PLLA1_MISC0,
+	.iddq_bit_idx = PLLCX_IDDQ_BIT,
+	.reset_reg = PLLA1_MISC0,
+	.reset_bit_idx = PLLCX_RESET_BIT,
+	.round_p_to_pdiv = pll_qlin_p_to_pdiv,
+	.pdiv_tohw = pll_qlin_pdiv_to_hw,
+	.div_nmp = &pllc_nmp,
+	.ext_misc_reg[0] = PLLA1_MISC0,
+	.ext_misc_reg[1] = PLLA1_MISC1,
+	.ext_misc_reg[2] = PLLA1_MISC2,
+	.ext_misc_reg[3] = PLLA1_MISC3,
+	.freq_table = pll_cx_freq_table,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+	.set_defaults = _plla1_set_defaults,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+static struct div_nmp plla_nmp = {
+	.divm_shift = 0,
+	.divm_width = 8,
+	.divn_shift = 8,
+	.divn_width = 8,
+	.divp_shift = 20,
+	.divp_width = 5,
+};
+
+static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
+	{ 12000000, 282240000, 47, 1, 1, 1, 0xf148 }, /* actual: 282240234 */
+	{ 12000000, 368640000, 61, 1, 1, 1, 0xfe15 }, /* actual: 368640381 */
+	{ 12000000, 240000000, 60, 1, 2, 1,      0 },
+	{ 13000000, 282240000, 43, 1, 1, 1, 0xfd7d }, /* actual: 282239807 */
+	{ 13000000, 368640000, 56, 1, 1, 1, 0x06d8 }, /* actual: 368640137 */
+	{ 13000000, 240000000, 55, 1, 2, 1,      0 }, /* actual: 238.3 MHz */
+	{ 38400000, 282240000, 44, 3, 1, 1, 0xf333 }, /* actual: 282239844 */
+	{ 38400000, 368640000, 57, 3, 1, 1, 0x0333 }, /* actual: 368639844 */
+	{ 38400000, 240000000, 75, 3, 3, 1,      0 },
+	{        0,         0,  0, 0, 0, 0,      0 },
+};
+
+static struct tegra_clk_pll_params pll_a_params = {
+	.input_min = 12000000,
+	.input_max = 800000000,
+	.cf_min = 12000000,
+	.cf_max = 19200000,
+	.vco_min = 500000000,
+	.vco_max = 1000000000,
+	.base_reg = PLLA_BASE,
+	.misc_reg = PLLA_MISC0,
+	.lock_mask = PLL_BASE_LOCK,
+	.lock_enable_bit_idx = PLLA_MISC_LOCK_ENABLE,
+	.lock_delay = 300,
+	.round_p_to_pdiv = pll_qlin_p_to_pdiv,
+	.pdiv_tohw = pll_qlin_pdiv_to_hw,
+	.iddq_reg = PLLA_BASE,
+	.iddq_bit_idx = PLLA_IDDQ_BIT,
+	.div_nmp = &plla_nmp,
+	.sdm_din_reg = PLLA_MISC1,
+	.sdm_din_mask = PLLA_SDM_DIN_MASK,
+	.sdm_ctrl_reg = PLLA_MISC2,
+	.sdm_ctrl_en_mask = PLLA_SDM_EN_MASK,
+	.ext_misc_reg[0] = PLLA_MISC0,
+	.ext_misc_reg[1] = PLLA_MISC1,
+	.ext_misc_reg[2] = PLLA_MISC2,
+	.freq_table = pll_a_freq_table,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_MDIV_NEW |
+		 TEGRA_PLL_HAS_LOCK_ENABLE,
+	.set_defaults = tegra210_plla_set_defaults,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+	.set_gain = tegra210_clk_pll_set_gain,
+	.adjust_vco = tegra210_clk_adjust_vco_min,
+};
+
+static struct div_nmp plld_nmp = {
+	.divm_shift = 0,
+	.divm_width = 8,
+	.divn_shift = 11,
+	.divn_width = 8,
+	.divp_shift = 20,
+	.divp_width = 3,
+};
+
+static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
+	{ 12000000, 594000000, 99, 1, 1, 0,      0 },
+	{ 13000000, 594000000, 91, 1, 1, 0, 0xfc4f }, /* actual: 594000183 */
+	{ 38400000, 594000000, 30, 1, 1, 0, 0x0e00 },
+	{        0,         0,  0, 0, 0, 0,      0 },
+};
+
+static struct tegra_clk_pll_params pll_d_params = {
+	.input_min = 12000000,
+	.input_max = 800000000,
+	.cf_min = 12000000,
+	.cf_max = 38400000,
+	.vco_min = 750000000,
+	.vco_max = 1500000000,
+	.base_reg = PLLD_BASE,
+	.misc_reg = PLLD_MISC0,
+	.lock_mask = PLL_BASE_LOCK,
+	.lock_enable_bit_idx = PLLD_MISC_LOCK_ENABLE,
+	.lock_delay = 1000,
+	.iddq_reg = PLLD_MISC0,
+	.iddq_bit_idx = PLLD_IDDQ_BIT,
+	.round_p_to_pdiv = pll_expo_p_to_pdiv,
+	.pdiv_tohw = pll_expo_pdiv_to_hw,
+	.div_nmp = &plld_nmp,
+	.sdm_din_reg = PLLD_MISC0,
+	.sdm_din_mask = PLLA_SDM_DIN_MASK,
+	.sdm_ctrl_reg = PLLD_MISC0,
+	.sdm_ctrl_en_mask = PLLD_SDM_EN_MASK,
+	.ext_misc_reg[0] = PLLD_MISC0,
+	.ext_misc_reg[1] = PLLD_MISC1,
+	.freq_table = pll_d_freq_table,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+	.mdiv_default = 1,
+	.set_defaults = tegra210_plld_set_defaults,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+	.set_gain = tegra210_clk_pll_set_gain,
+	.adjust_vco = tegra210_clk_adjust_vco_min,
+};
+
+static struct tegra_clk_pll_freq_table tegra210_pll_d2_freq_table[] = {
+	{ 12000000, 594000000, 99, 1, 1, 0, 0xf000 },
+	{ 13000000, 594000000, 91, 1, 1, 0, 0xfc4f }, /* actual: 594000183 */
+	{ 38400000, 594000000, 30, 1, 1, 0, 0x0e00 },
+	{        0,         0,  0, 0, 0, 0,      0 },
+};
+
+/* s/w policy, always tegra_pll_ref */
+static struct tegra_clk_pll_params pll_d2_params = {
+	.input_min = 12000000,
+	.input_max = 800000000,
+	.cf_min = 12000000,
+	.cf_max = 38400000,
+	.vco_min = 750000000,
+	.vco_max = 1500000000,
+	.base_reg = PLLD2_BASE,
+	.misc_reg = PLLD2_MISC0,
+	.lock_mask = PLL_BASE_LOCK,
+	.lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE,
+	.lock_delay = 300,
+	.iddq_reg = PLLD2_BASE,
+	.iddq_bit_idx = PLLSS_IDDQ_BIT,
+	.sdm_din_reg = PLLD2_MISC3,
+	.sdm_din_mask = PLLA_SDM_DIN_MASK,
+	.sdm_ctrl_reg = PLLD2_MISC1,
+	.sdm_ctrl_en_mask = PLLD2_SDM_EN_MASK,
+	.ssc_ctrl_reg = PLLD2_MISC1,
+	.ssc_ctrl_en_mask = PLLD2_SSC_EN_MASK,
+	.round_p_to_pdiv = pll_qlin_p_to_pdiv,
+	.pdiv_tohw = pll_qlin_pdiv_to_hw,
+	.div_nmp = &pllss_nmp,
+	.ext_misc_reg[0] = PLLD2_MISC0,
+	.ext_misc_reg[1] = PLLD2_MISC1,
+	.ext_misc_reg[2] = PLLD2_MISC2,
+	.ext_misc_reg[3] = PLLD2_MISC3,
+	.max_p = PLL_QLIN_PDIV_MAX,
+	.mdiv_default = 1,
+	.freq_table = tegra210_pll_d2_freq_table,
+	.set_defaults = tegra210_plld2_set_defaults,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+	.set_gain = tegra210_clk_pll_set_gain,
+	.adjust_vco = tegra210_clk_adjust_vco_min,
+};
+
+static struct tegra_clk_pll_freq_table pll_dp_freq_table[] = {
+	{ 12000000, 270000000, 90, 1, 3, 0, 0xf000 },
+	{ 13000000, 270000000, 83, 1, 3, 0, 0xf000 }, /* actual: 269.8 MHz */
+	{ 38400000, 270000000, 28, 1, 3, 0, 0xf400 },
+	{        0,         0,  0, 0, 0, 0,      0 },
+};
+
+static struct tegra_clk_pll_params pll_dp_params = {
+	.input_min = 12000000,
+	.input_max = 800000000,
+	.cf_min = 12000000,
+	.cf_max = 38400000,
+	.vco_min = 750000000,
+	.vco_max = 1500000000,
+	.base_reg = PLLDP_BASE,
+	.misc_reg = PLLDP_MISC,
+	.lock_mask = PLL_BASE_LOCK,
+	.lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE,
+	.lock_delay = 300,
+	.iddq_reg = PLLDP_BASE,
+	.iddq_bit_idx = PLLSS_IDDQ_BIT,
+	.sdm_din_reg = PLLDP_SS_CTRL2,
+	.sdm_din_mask = PLLA_SDM_DIN_MASK,
+	.sdm_ctrl_reg = PLLDP_SS_CFG,
+	.sdm_ctrl_en_mask = PLLDP_SDM_EN_MASK,
+	.ssc_ctrl_reg = PLLDP_SS_CFG,
+	.ssc_ctrl_en_mask = PLLDP_SSC_EN_MASK,
+	.round_p_to_pdiv = pll_qlin_p_to_pdiv,
+	.pdiv_tohw = pll_qlin_pdiv_to_hw,
+	.div_nmp = &pllss_nmp,
+	.ext_misc_reg[0] = PLLDP_MISC,
+	.ext_misc_reg[1] = PLLDP_SS_CFG,
+	.ext_misc_reg[2] = PLLDP_SS_CTRL1,
+	.ext_misc_reg[3] = PLLDP_SS_CTRL2,
+	.max_p = PLL_QLIN_PDIV_MAX,
+	.mdiv_default = 1,
+	.freq_table = pll_dp_freq_table,
+	.set_defaults = tegra210_plldp_set_defaults,
+	.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+	.set_gain = tegra210_clk_pll_set_gain,
+	.adjust_vco = tegra210_clk_adjust_vco_min,
+};
+
+static struct div_nmp pllu_nmp = {
+	.divm_shift = 0,
+	.divm_width = 8,
+	.divn_shift = 8,
+	.divn_width = 8,
+	.divp_shift = 16,
+	.divp_width = 5,
+};
+
+static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
+	{ 12000000, 480000000, 40, 1, 0, 0 },
+	{ 13000000, 480000000, 36, 1, 0, 0 }, /* actual: 468.0 MHz */
+	{ 38400000, 480000000, 25, 2, 0, 0 },
+	{        0,         0,  0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_params pll_u_vco_params = {
+	.input_min = 9600000,
+	.input_max = 800000000,
+	.cf_min = 9600000,
+	.cf_max = 19200000,
+	.vco_min = 350000000,
+	.vco_max = 700000000,
+	.base_reg = PLLU_BASE,
+	.misc_reg = PLLU_MISC0,
+	.lock_mask = PLL_BASE_LOCK,
+	.lock_enable_bit_idx = PLLU_MISC_LOCK_ENABLE,
+	.lock_delay = 1000,
+	.iddq_reg = PLLU_MISC0,
+	.iddq_bit_idx = PLLU_IDDQ_BIT,
+	.ext_misc_reg[0] = PLLU_MISC0,
+	.ext_misc_reg[1] = PLLU_MISC1,
+	.round_p_to_pdiv = pll_qlin_p_to_pdiv,
+	.pdiv_tohw = pll_qlin_pdiv_to_hw,
+	.div_nmp = &pllu_nmp,
+	.freq_table = pll_u_freq_table,
+	.flags = TEGRA_PLLU | TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
+		 TEGRA_PLL_VCO_OUT,
+	.set_defaults = tegra210_pllu_set_defaults,
+	.calc_rate = tegra210_pll_fixed_mdiv_cfg,
+};
+
+struct utmi_clk_param {
+	/* Oscillator Frequency in KHz */
+	u32 osc_frequency;
+	/* UTMIP PLL Enable Delay Count  */
+	u8 enable_delay_count;
+	/* UTMIP PLL Stable count */
+	u16 stable_count;
+	/*  UTMIP PLL Active delay count */
+	u8 active_delay_count;
+	/* UTMIP PLL Xtal frequency count */
+	u16 xtal_freq_count;
+};
+
+static const struct utmi_clk_param utmi_parameters[] = {
+	{
+		.osc_frequency = 38400000, .enable_delay_count = 0x0,
+		.stable_count = 0x0, .active_delay_count = 0x6,
+		.xtal_freq_count = 0x80
+	}, {
+		.osc_frequency = 13000000, .enable_delay_count = 0x02,
+		.stable_count = 0x33, .active_delay_count = 0x05,
+		.xtal_freq_count = 0x7f
+	}, {
+		.osc_frequency = 19200000, .enable_delay_count = 0x03,
+		.stable_count = 0x4b, .active_delay_count = 0x06,
+		.xtal_freq_count = 0xbb
+	}, {
+		.osc_frequency = 12000000, .enable_delay_count = 0x02,
+		.stable_count = 0x2f, .active_delay_count = 0x08,
+		.xtal_freq_count = 0x76
+	}, {
+		.osc_frequency = 26000000, .enable_delay_count = 0x04,
+		.stable_count = 0x66, .active_delay_count = 0x09,
+		.xtal_freq_count = 0xfe
+	}, {
+		.osc_frequency = 16800000, .enable_delay_count = 0x03,
+		.stable_count = 0x41, .active_delay_count = 0x0a,
+		.xtal_freq_count = 0xa4
+	},
+};
+
+static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
+	[tegra_clk_ispb] = { .dt_id = TEGRA210_CLK_ISPB, .present = true },
+	[tegra_clk_rtc] = { .dt_id = TEGRA210_CLK_RTC, .present = true },
+	[tegra_clk_timer] = { .dt_id = TEGRA210_CLK_TIMER, .present = true },
+	[tegra_clk_uarta_8] = { .dt_id = TEGRA210_CLK_UARTA, .present = true },
+	[tegra_clk_sdmmc2_9] = { .dt_id = TEGRA210_CLK_SDMMC2, .present = true },
+	[tegra_clk_i2s1] = { .dt_id = TEGRA210_CLK_I2S1, .present = true },
+	[tegra_clk_i2c1] = { .dt_id = TEGRA210_CLK_I2C1, .present = true },
+	[tegra_clk_sdmmc1_9] = { .dt_id = TEGRA210_CLK_SDMMC1, .present = true },
+	[tegra_clk_sdmmc4_9] = { .dt_id = TEGRA210_CLK_SDMMC4, .present = true },
+	[tegra_clk_pwm] = { .dt_id = TEGRA210_CLK_PWM, .present = true },
+	[tegra_clk_i2s2] = { .dt_id = TEGRA210_CLK_I2S2, .present = true },
+	[tegra_clk_usbd] = { .dt_id = TEGRA210_CLK_USBD, .present = true },
+	[tegra_clk_isp_9] = { .dt_id = TEGRA210_CLK_ISP, .present = true },
+	[tegra_clk_disp2_8] = { .dt_id = TEGRA210_CLK_DISP2, .present = true },
+	[tegra_clk_disp1_8] = { .dt_id = TEGRA210_CLK_DISP1, .present = true },
+	[tegra_clk_host1x_9] = { .dt_id = TEGRA210_CLK_HOST1X, .present = true },
+	[tegra_clk_i2s0] = { .dt_id = TEGRA210_CLK_I2S0, .present = true },
+	[tegra_clk_apbdma] = { .dt_id = TEGRA210_CLK_APBDMA, .present = true },
+	[tegra_clk_kfuse] = { .dt_id = TEGRA210_CLK_KFUSE, .present = true },
+	[tegra_clk_sbc1_9] = { .dt_id = TEGRA210_CLK_SBC1, .present = true },
+	[tegra_clk_sbc2_9] = { .dt_id = TEGRA210_CLK_SBC2, .present = true },
+	[tegra_clk_sbc3_9] = { .dt_id = TEGRA210_CLK_SBC3, .present = true },
+	[tegra_clk_i2c5] = { .dt_id = TEGRA210_CLK_I2C5, .present = true },
+	[tegra_clk_csi] = { .dt_id = TEGRA210_CLK_CSI, .present = true },
+	[tegra_clk_i2c2] = { .dt_id = TEGRA210_CLK_I2C2, .present = true },
+	[tegra_clk_uartc_8] = { .dt_id = TEGRA210_CLK_UARTC, .present = true },
+	[tegra_clk_mipi_cal] = { .dt_id = TEGRA210_CLK_MIPI_CAL, .present = true },
+	[tegra_clk_emc] = { .dt_id = TEGRA210_CLK_EMC, .present = true },
+	[tegra_clk_usb2] = { .dt_id = TEGRA210_CLK_USB2, .present = true },
+	[tegra_clk_bsev] = { .dt_id = TEGRA210_CLK_BSEV, .present = true },
+	[tegra_clk_uartd_8] = { .dt_id = TEGRA210_CLK_UARTD, .present = true },
+	[tegra_clk_i2c3] = { .dt_id = TEGRA210_CLK_I2C3, .present = true },
+	[tegra_clk_sbc4_9] = { .dt_id = TEGRA210_CLK_SBC4, .present = true },
+	[tegra_clk_sdmmc3_9] = { .dt_id = TEGRA210_CLK_SDMMC3, .present = true },
+	[tegra_clk_pcie] = { .dt_id = TEGRA210_CLK_PCIE, .present = true },
+	[tegra_clk_owr_8] = { .dt_id = TEGRA210_CLK_OWR, .present = true },
+	[tegra_clk_afi] = { .dt_id = TEGRA210_CLK_AFI, .present = true },
+	[tegra_clk_csite_8] = { .dt_id = TEGRA210_CLK_CSITE, .present = true },
+	[tegra_clk_soc_therm_8] = { .dt_id = TEGRA210_CLK_SOC_THERM, .present = true },
+	[tegra_clk_dtv] = { .dt_id = TEGRA210_CLK_DTV, .present = true },
+	[tegra_clk_i2cslow] = { .dt_id = TEGRA210_CLK_I2CSLOW, .present = true },
+	[tegra_clk_tsec_8] = { .dt_id = TEGRA210_CLK_TSEC, .present = true },
+	[tegra_clk_xusb_host] = { .dt_id = TEGRA210_CLK_XUSB_HOST, .present = true },
+	[tegra_clk_csus] = { .dt_id = TEGRA210_CLK_CSUS, .present = true },
+	[tegra_clk_mselect] = { .dt_id = TEGRA210_CLK_MSELECT, .present = true },
+	[tegra_clk_tsensor] = { .dt_id = TEGRA210_CLK_TSENSOR, .present = true },
+	[tegra_clk_i2s3] = { .dt_id = TEGRA210_CLK_I2S3, .present = true },
+	[tegra_clk_i2s4] = { .dt_id = TEGRA210_CLK_I2S4, .present = true },
+	[tegra_clk_i2c4] = { .dt_id = TEGRA210_CLK_I2C4, .present = true },
+	[tegra_clk_d_audio] = { .dt_id = TEGRA210_CLK_D_AUDIO, .present = true },
+	[tegra_clk_hda2codec_2x_8] = { .dt_id = TEGRA210_CLK_HDA2CODEC_2X, .present = true },
+	[tegra_clk_spdif_2x] = { .dt_id = TEGRA210_CLK_SPDIF_2X, .present = true },
+	[tegra_clk_actmon] = { .dt_id = TEGRA210_CLK_ACTMON, .present = true },
+	[tegra_clk_extern1] = { .dt_id = TEGRA210_CLK_EXTERN1, .present = true },
+	[tegra_clk_extern2] = { .dt_id = TEGRA210_CLK_EXTERN2, .present = true },
+	[tegra_clk_extern3] = { .dt_id = TEGRA210_CLK_EXTERN3, .present = true },
+	[tegra_clk_sata_oob_8] = { .dt_id = TEGRA210_CLK_SATA_OOB, .present = true },
+	[tegra_clk_sata_8] = { .dt_id = TEGRA210_CLK_SATA, .present = true },
+	[tegra_clk_hda_8] = { .dt_id = TEGRA210_CLK_HDA, .present = true },
+	[tegra_clk_hda2hdmi] = { .dt_id = TEGRA210_CLK_HDA2HDMI, .present = true },
+	[tegra_clk_cilab] = { .dt_id = TEGRA210_CLK_CILAB, .present = true },
+	[tegra_clk_cilcd] = { .dt_id = TEGRA210_CLK_CILCD, .present = true },
+	[tegra_clk_cile] = { .dt_id = TEGRA210_CLK_CILE, .present = true },
+	[tegra_clk_dsialp] = { .dt_id = TEGRA210_CLK_DSIALP, .present = true },
+	[tegra_clk_dsiblp] = { .dt_id = TEGRA210_CLK_DSIBLP, .present = true },
+	[tegra_clk_entropy_8] = { .dt_id = TEGRA210_CLK_ENTROPY, .present = true },
+	[tegra_clk_xusb_ss] = { .dt_id = TEGRA210_CLK_XUSB_SS, .present = true },
+	[tegra_clk_i2c6] = { .dt_id = TEGRA210_CLK_I2C6, .present = true },
+	[tegra_clk_vim2_clk] = { .dt_id = TEGRA210_CLK_VIM2_CLK, .present = true },
+	[tegra_clk_clk72Mhz_8] = { .dt_id = TEGRA210_CLK_CLK72MHZ, .present = true },
+	[tegra_clk_vic03_8] = { .dt_id = TEGRA210_CLK_VIC03, .present = true },
+	[tegra_clk_dpaux] = { .dt_id = TEGRA210_CLK_DPAUX, .present = true },
+	[tegra_clk_sor0] = { .dt_id = TEGRA210_CLK_SOR0, .present = true },
+	[tegra_clk_sor0_lvds] = { .dt_id = TEGRA210_CLK_SOR0_LVDS, .present = true },
+	[tegra_clk_gpu] = { .dt_id = TEGRA210_CLK_GPU, .present = true },
+	[tegra_clk_pll_g_ref] = { .dt_id = TEGRA210_CLK_PLL_G_REF, .present = true, },
+	[tegra_clk_uartb_8] = { .dt_id = TEGRA210_CLK_UARTB, .present = true },
+	[tegra_clk_vfir] = { .dt_id = TEGRA210_CLK_VFIR, .present = true },
+	[tegra_clk_spdif_in_8] = { .dt_id = TEGRA210_CLK_SPDIF_IN, .present = true },
+	[tegra_clk_spdif_out] = { .dt_id = TEGRA210_CLK_SPDIF_OUT, .present = true },
+	[tegra_clk_vi_10] = { .dt_id = TEGRA210_CLK_VI, .present = true },
+	[tegra_clk_vi_sensor_8] = { .dt_id = TEGRA210_CLK_VI_SENSOR, .present = true },
+	[tegra_clk_fuse] = { .dt_id = TEGRA210_CLK_FUSE, .present = true },
+	[tegra_clk_fuse_burn] = { .dt_id = TEGRA210_CLK_FUSE_BURN, .present = true },
+	[tegra_clk_clk_32k] = { .dt_id = TEGRA210_CLK_CLK_32K, .present = true },
+	[tegra_clk_clk_m] = { .dt_id = TEGRA210_CLK_CLK_M, .present = true },
+	[tegra_clk_clk_m_div2] = { .dt_id = TEGRA210_CLK_CLK_M_DIV2, .present = true },
+	[tegra_clk_clk_m_div4] = { .dt_id = TEGRA210_CLK_CLK_M_DIV4, .present = true },
+	[tegra_clk_pll_ref] = { .dt_id = TEGRA210_CLK_PLL_REF, .present = true },
+	[tegra_clk_pll_c] = { .dt_id = TEGRA210_CLK_PLL_C, .present = true },
+	[tegra_clk_pll_c_out1] = { .dt_id = TEGRA210_CLK_PLL_C_OUT1, .present = true },
+	[tegra_clk_pll_c2] = { .dt_id = TEGRA210_CLK_PLL_C2, .present = true },
+	[tegra_clk_pll_c3] = { .dt_id = TEGRA210_CLK_PLL_C3, .present = true },
+	[tegra_clk_pll_m] = { .dt_id = TEGRA210_CLK_PLL_M, .present = true },
+	[tegra_clk_pll_m_out1] = { .dt_id = TEGRA210_CLK_PLL_M_OUT1, .present = true },
+	[tegra_clk_pll_p] = { .dt_id = TEGRA210_CLK_PLL_P, .present = true },
+	[tegra_clk_pll_p_out1] = { .dt_id = TEGRA210_CLK_PLL_P_OUT1, .present = true },
+	[tegra_clk_pll_p_out3] = { .dt_id = TEGRA210_CLK_PLL_P_OUT3, .present = true },
+	[tegra_clk_pll_p_out4_cpu] = { .dt_id = TEGRA210_CLK_PLL_P_OUT4, .present = true },
+	[tegra_clk_pll_p_out_hsio] = { .dt_id = TEGRA210_CLK_PLL_P_OUT_HSIO, .present = true },
+	[tegra_clk_pll_p_out_xusb] = { .dt_id = TEGRA210_CLK_PLL_P_OUT_XUSB, .present = true },
+	[tegra_clk_pll_p_out_cpu] = { .dt_id = TEGRA210_CLK_PLL_P_OUT_CPU, .present = true },
+	[tegra_clk_pll_p_out_adsp] = { .dt_id = TEGRA210_CLK_PLL_P_OUT_ADSP, .present = true },
+	[tegra_clk_pll_a] = { .dt_id = TEGRA210_CLK_PLL_A, .present = true },
+	[tegra_clk_pll_a_out0] = { .dt_id = TEGRA210_CLK_PLL_A_OUT0, .present = true },
+	[tegra_clk_pll_d] = { .dt_id = TEGRA210_CLK_PLL_D, .present = true },
+	[tegra_clk_pll_d_out0] = { .dt_id = TEGRA210_CLK_PLL_D_OUT0, .present = true },
+	[tegra_clk_pll_d2] = { .dt_id = TEGRA210_CLK_PLL_D2, .present = true },
+	[tegra_clk_pll_d2_out0] = { .dt_id = TEGRA210_CLK_PLL_D2_OUT0, .present = true },
+	[tegra_clk_pll_u] = { .dt_id = TEGRA210_CLK_PLL_U, .present = true },
+	[tegra_clk_pll_u_out] = { .dt_id = TEGRA210_CLK_PLL_U_OUT, .present = true },
+	[tegra_clk_pll_u_out1] = { .dt_id = TEGRA210_CLK_PLL_U_OUT1, .present = true },
+	[tegra_clk_pll_u_out2] = { .dt_id = TEGRA210_CLK_PLL_U_OUT2, .present = true },
+	[tegra_clk_pll_u_480m] = { .dt_id = TEGRA210_CLK_PLL_U_480M, .present = true },
+	[tegra_clk_pll_u_60m] = { .dt_id = TEGRA210_CLK_PLL_U_60M, .present = true },
+	[tegra_clk_pll_u_48m] = { .dt_id = TEGRA210_CLK_PLL_U_48M, .present = true },
+	[tegra_clk_pll_x] = { .dt_id = TEGRA210_CLK_PLL_X, .present = true },
+	[tegra_clk_pll_x_out0] = { .dt_id = TEGRA210_CLK_PLL_X_OUT0, .present = true },
+	[tegra_clk_pll_re_vco] = { .dt_id = TEGRA210_CLK_PLL_RE_VCO, .present = true },
+	[tegra_clk_pll_re_out] = { .dt_id = TEGRA210_CLK_PLL_RE_OUT, .present = true },
+	[tegra_clk_spdif_in_sync] = { .dt_id = TEGRA210_CLK_SPDIF_IN_SYNC, .present = true },
+	[tegra_clk_i2s0_sync] = { .dt_id = TEGRA210_CLK_I2S0_SYNC, .present = true },
+	[tegra_clk_i2s1_sync] = { .dt_id = TEGRA210_CLK_I2S1_SYNC, .present = true },
+	[tegra_clk_i2s2_sync] = { .dt_id = TEGRA210_CLK_I2S2_SYNC, .present = true },
+	[tegra_clk_i2s3_sync] = { .dt_id = TEGRA210_CLK_I2S3_SYNC, .present = true },
+	[tegra_clk_i2s4_sync] = { .dt_id = TEGRA210_CLK_I2S4_SYNC, .present = true },
+	[tegra_clk_vimclk_sync] = { .dt_id = TEGRA210_CLK_VIMCLK_SYNC, .present = true },
+	[tegra_clk_audio0] = { .dt_id = TEGRA210_CLK_AUDIO0, .present = true },
+	[tegra_clk_audio1] = { .dt_id = TEGRA210_CLK_AUDIO1, .present = true },
+	[tegra_clk_audio2] = { .dt_id = TEGRA210_CLK_AUDIO2, .present = true },
+	[tegra_clk_audio3] = { .dt_id = TEGRA210_CLK_AUDIO3, .present = true },
+	[tegra_clk_audio4] = { .dt_id = TEGRA210_CLK_AUDIO4, .present = true },
+	[tegra_clk_spdif] = { .dt_id = TEGRA210_CLK_SPDIF, .present = true },
+	[tegra_clk_clk_out_1] = { .dt_id = TEGRA210_CLK_CLK_OUT_1, .present = true },
+	[tegra_clk_clk_out_2] = { .dt_id = TEGRA210_CLK_CLK_OUT_2, .present = true },
+	[tegra_clk_clk_out_3] = { .dt_id = TEGRA210_CLK_CLK_OUT_3, .present = true },
+	[tegra_clk_blink] = { .dt_id = TEGRA210_CLK_BLINK, .present = true },
+	[tegra_clk_xusb_gate] = { .dt_id = TEGRA210_CLK_XUSB_GATE, .present = true },
+	[tegra_clk_xusb_host_src_8] = { .dt_id = TEGRA210_CLK_XUSB_HOST_SRC, .present = true },
+	[tegra_clk_xusb_falcon_src_8] = { .dt_id = TEGRA210_CLK_XUSB_FALCON_SRC, .present = true },
+	[tegra_clk_xusb_fs_src] = { .dt_id = TEGRA210_CLK_XUSB_FS_SRC, .present = true },
+	[tegra_clk_xusb_ss_src_8] = { .dt_id = TEGRA210_CLK_XUSB_SS_SRC, .present = true },
+	[tegra_clk_xusb_ss_div2] = { .dt_id = TEGRA210_CLK_XUSB_SS_DIV2, .present = true },
+	[tegra_clk_xusb_dev_src_8] = { .dt_id = TEGRA210_CLK_XUSB_DEV_SRC, .present = true },
+	[tegra_clk_xusb_dev] = { .dt_id = TEGRA210_CLK_XUSB_DEV, .present = true },
+	[tegra_clk_xusb_hs_src_4] = { .dt_id = TEGRA210_CLK_XUSB_HS_SRC, .present = true },
+	[tegra_clk_xusb_ssp_src] = { .dt_id = TEGRA210_CLK_XUSB_SSP_SRC, .present = true },
+	[tegra_clk_usb2_hsic_trk] = { .dt_id = TEGRA210_CLK_USB2_HSIC_TRK, .present = true },
+	[tegra_clk_hsic_trk] = { .dt_id = TEGRA210_CLK_HSIC_TRK, .present = true },
+	[tegra_clk_usb2_trk] = { .dt_id = TEGRA210_CLK_USB2_TRK, .present = true },
+	[tegra_clk_sclk] = { .dt_id = TEGRA210_CLK_SCLK, .present = true },
+	[tegra_clk_sclk_mux] = { .dt_id = TEGRA210_CLK_SCLK_MUX, .present = true },
+	[tegra_clk_hclk] = { .dt_id = TEGRA210_CLK_HCLK, .present = true },
+	[tegra_clk_pclk] = { .dt_id = TEGRA210_CLK_PCLK, .present = true },
+	[tegra_clk_cclk_g] = { .dt_id = TEGRA210_CLK_CCLK_G, .present = true },
+	[tegra_clk_cclk_lp] = { .dt_id = TEGRA210_CLK_CCLK_LP, .present = true },
+	[tegra_clk_dfll_ref] = { .dt_id = TEGRA210_CLK_DFLL_REF, .present = true },
+	[tegra_clk_dfll_soc] = { .dt_id = TEGRA210_CLK_DFLL_SOC, .present = true },
+	[tegra_clk_vi_sensor2_8] = { .dt_id = TEGRA210_CLK_VI_SENSOR2, .present = true },
+	[tegra_clk_pll_p_out5] = { .dt_id = TEGRA210_CLK_PLL_P_OUT5, .present = true },
+	[tegra_clk_pll_c4] = { .dt_id = TEGRA210_CLK_PLL_C4, .present = true },
+	[tegra_clk_pll_dp] = { .dt_id = TEGRA210_CLK_PLL_DP, .present = true },
+	[tegra_clk_audio0_mux] = { .dt_id = TEGRA210_CLK_AUDIO0_MUX, .present = true },
+	[tegra_clk_audio1_mux] = { .dt_id = TEGRA210_CLK_AUDIO1_MUX, .present = true },
+	[tegra_clk_audio2_mux] = { .dt_id = TEGRA210_CLK_AUDIO2_MUX, .present = true },
+	[tegra_clk_audio3_mux] = { .dt_id = TEGRA210_CLK_AUDIO3_MUX, .present = true },
+	[tegra_clk_audio4_mux] = { .dt_id = TEGRA210_CLK_AUDIO4_MUX, .present = true },
+	[tegra_clk_spdif_mux] = { .dt_id = TEGRA210_CLK_SPDIF_MUX, .present = true },
+	[tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_1_MUX, .present = true },
+	[tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_2_MUX, .present = true },
+	[tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_3_MUX, .present = true },
+	[tegra_clk_maud] = { .dt_id = TEGRA210_CLK_MAUD, .present = true },
+	[tegra_clk_mipibif] = { .dt_id = TEGRA210_CLK_MIPIBIF, .present = true },
+	[tegra_clk_qspi] = { .dt_id = TEGRA210_CLK_QSPI, .present = true },
+	[tegra_clk_sdmmc_legacy] = { .dt_id = TEGRA210_CLK_SDMMC_LEGACY, .present = true },
+	[tegra_clk_tsecb] = { .dt_id = TEGRA210_CLK_TSECB, .present = true },
+	[tegra_clk_uartape] = { .dt_id = TEGRA210_CLK_UARTAPE, .present = true },
+	[tegra_clk_vi_i2c] = { .dt_id = TEGRA210_CLK_VI_I2C, .present = true },
+	[tegra_clk_ape] = { .dt_id = TEGRA210_CLK_APE, .present = true },
+	[tegra_clk_dbgapb] = { .dt_id = TEGRA210_CLK_DBGAPB, .present = true },
+	[tegra_clk_nvdec] = { .dt_id = TEGRA210_CLK_NVDEC, .present = true },
+	[tegra_clk_nvenc] = { .dt_id = TEGRA210_CLK_NVENC, .present = true },
+	[tegra_clk_nvjpg] = { .dt_id = TEGRA210_CLK_NVJPG, .present = true },
+	[tegra_clk_pll_c4_out0] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT0, .present = true },
+	[tegra_clk_pll_c4_out1] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT1, .present = true },
+	[tegra_clk_pll_c4_out2] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT2, .present = true },
+	[tegra_clk_pll_c4_out3] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT3, .present = true },
+};
+
+static struct tegra_devclk devclks[] __initdata = {
+	{ .con_id = "clk_m", .dt_id = TEGRA210_CLK_CLK_M },
+	{ .con_id = "pll_ref", .dt_id = TEGRA210_CLK_PLL_REF },
+	{ .con_id = "clk_32k", .dt_id = TEGRA210_CLK_CLK_32K },
+	{ .con_id = "clk_m_div2", .dt_id = TEGRA210_CLK_CLK_M_DIV2 },
+	{ .con_id = "clk_m_div4", .dt_id = TEGRA210_CLK_CLK_M_DIV4 },
+	{ .con_id = "pll_c", .dt_id = TEGRA210_CLK_PLL_C },
+	{ .con_id = "pll_c_out1", .dt_id = TEGRA210_CLK_PLL_C_OUT1 },
+	{ .con_id = "pll_c2", .dt_id = TEGRA210_CLK_PLL_C2 },
+	{ .con_id = "pll_c3", .dt_id = TEGRA210_CLK_PLL_C3 },
+	{ .con_id = "pll_p", .dt_id = TEGRA210_CLK_PLL_P },
+	{ .con_id = "pll_p_out1", .dt_id = TEGRA210_CLK_PLL_P_OUT1 },
+	{ .con_id = "pll_p_out2", .dt_id = TEGRA210_CLK_PLL_P_OUT2 },
+	{ .con_id = "pll_p_out3", .dt_id = TEGRA210_CLK_PLL_P_OUT3 },
+	{ .con_id = "pll_p_out4", .dt_id = TEGRA210_CLK_PLL_P_OUT4 },
+	{ .con_id = "pll_m", .dt_id = TEGRA210_CLK_PLL_M },
+	{ .con_id = "pll_m_out1", .dt_id = TEGRA210_CLK_PLL_M_OUT1 },
+	{ .con_id = "pll_x", .dt_id = TEGRA210_CLK_PLL_X },
+	{ .con_id = "pll_x_out0", .dt_id = TEGRA210_CLK_PLL_X_OUT0 },
+	{ .con_id = "pll_u", .dt_id = TEGRA210_CLK_PLL_U },
+	{ .con_id = "pll_u_out", .dt_id = TEGRA210_CLK_PLL_U_OUT },
+	{ .con_id = "pll_u_out1", .dt_id = TEGRA210_CLK_PLL_U_OUT1 },
+	{ .con_id = "pll_u_out2", .dt_id = TEGRA210_CLK_PLL_U_OUT2 },
+	{ .con_id = "pll_u_480M", .dt_id = TEGRA210_CLK_PLL_U_480M },
+	{ .con_id = "pll_u_60M", .dt_id = TEGRA210_CLK_PLL_U_60M },
+	{ .con_id = "pll_u_48M", .dt_id = TEGRA210_CLK_PLL_U_48M },
+	{ .con_id = "pll_d", .dt_id = TEGRA210_CLK_PLL_D },
+	{ .con_id = "pll_d_out0", .dt_id = TEGRA210_CLK_PLL_D_OUT0 },
+	{ .con_id = "pll_d2", .dt_id = TEGRA210_CLK_PLL_D2 },
+	{ .con_id = "pll_d2_out0", .dt_id = TEGRA210_CLK_PLL_D2_OUT0 },
+	{ .con_id = "pll_a", .dt_id = TEGRA210_CLK_PLL_A },
+	{ .con_id = "pll_a_out0", .dt_id = TEGRA210_CLK_PLL_A_OUT0 },
+	{ .con_id = "pll_re_vco", .dt_id = TEGRA210_CLK_PLL_RE_VCO },
+	{ .con_id = "pll_re_out", .dt_id = TEGRA210_CLK_PLL_RE_OUT },
+	{ .con_id = "spdif_in_sync", .dt_id = TEGRA210_CLK_SPDIF_IN_SYNC },
+	{ .con_id = "i2s0_sync", .dt_id = TEGRA210_CLK_I2S0_SYNC },
+	{ .con_id = "i2s1_sync", .dt_id = TEGRA210_CLK_I2S1_SYNC },
+	{ .con_id = "i2s2_sync", .dt_id = TEGRA210_CLK_I2S2_SYNC },
+	{ .con_id = "i2s3_sync", .dt_id = TEGRA210_CLK_I2S3_SYNC },
+	{ .con_id = "i2s4_sync", .dt_id = TEGRA210_CLK_I2S4_SYNC },
+	{ .con_id = "vimclk_sync", .dt_id = TEGRA210_CLK_VIMCLK_SYNC },
+	{ .con_id = "audio0", .dt_id = TEGRA210_CLK_AUDIO0 },
+	{ .con_id = "audio1", .dt_id = TEGRA210_CLK_AUDIO1 },
+	{ .con_id = "audio2", .dt_id = TEGRA210_CLK_AUDIO2 },
+	{ .con_id = "audio3", .dt_id = TEGRA210_CLK_AUDIO3 },
+	{ .con_id = "audio4", .dt_id = TEGRA210_CLK_AUDIO4 },
+	{ .con_id = "spdif", .dt_id = TEGRA210_CLK_SPDIF },
+	{ .con_id = "spdif_2x", .dt_id = TEGRA210_CLK_SPDIF_2X },
+	{ .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA210_CLK_EXTERN1 },
+	{ .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA210_CLK_EXTERN2 },
+	{ .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA210_CLK_EXTERN3 },
+	{ .con_id = "blink", .dt_id = TEGRA210_CLK_BLINK },
+	{ .con_id = "cclk_g", .dt_id = TEGRA210_CLK_CCLK_G },
+	{ .con_id = "cclk_lp", .dt_id = TEGRA210_CLK_CCLK_LP },
+	{ .con_id = "sclk", .dt_id = TEGRA210_CLK_SCLK },
+	{ .con_id = "hclk", .dt_id = TEGRA210_CLK_HCLK },
+	{ .con_id = "pclk", .dt_id = TEGRA210_CLK_PCLK },
+	{ .con_id = "fuse", .dt_id = TEGRA210_CLK_FUSE },
+	{ .dev_id = "rtc-tegra", .dt_id = TEGRA210_CLK_RTC },
+	{ .dev_id = "timer", .dt_id = TEGRA210_CLK_TIMER },
+	{ .con_id = "pll_c4_out0", .dt_id = TEGRA210_CLK_PLL_C4_OUT0 },
+	{ .con_id = "pll_c4_out1", .dt_id = TEGRA210_CLK_PLL_C4_OUT1 },
+	{ .con_id = "pll_c4_out2", .dt_id = TEGRA210_CLK_PLL_C4_OUT2 },
+	{ .con_id = "pll_c4_out3", .dt_id = TEGRA210_CLK_PLL_C4_OUT3 },
+	{ .con_id = "dpaux", .dt_id = TEGRA210_CLK_DPAUX },
+	{ .con_id = "sor0", .dt_id = TEGRA210_CLK_SOR0 },
+};
+
+static struct tegra_audio_clk_info tegra210_audio_plls[] = {
+	{ "pll_a", &pll_a_params, tegra_clk_pll_a, "pll_ref" },
+	{ "pll_a1", &pll_a1_params, tegra_clk_pll_a1, "pll_ref" },
+};
+
+static struct clk **clks;
+
+static void tegra210_utmi_param_configure(void __iomem *clk_base)
+{
+	u32 reg;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
+		if (osc_freq == utmi_parameters[i].osc_frequency)
+			break;
+	}
+
+	if (i >= ARRAY_SIZE(utmi_parameters)) {
+		pr_err("%s: Unexpected oscillator freq %lu\n", __func__,
+		       osc_freq);
+		return;
+	}
+
+	reg = readl_relaxed(clk_base + PLLU_HW_PWRDN_CFG0);
+	reg |= PLLU_HW_PWRDN_CFG0_IDDQ_PD_INCLUDE |
+	       PLLU_HW_PWRDN_CFG0_USE_SWITCH_DETECT |
+	       PLLU_HW_PWRDN_CFG0_USE_LOCKDET;
+	reg &= ~(PLLU_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL |
+		  PLLU_HW_PWRDN_CFG0_CLK_SWITCH_SWCTL);
+	writel_relaxed(reg, clk_base + PLLU_HW_PWRDN_CFG0);
+
+	reg = readl_relaxed(clk_base + PLLU_HW_PWRDN_CFG0);
+	reg |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE;
+	writel_relaxed(reg, clk_base + PLLU_HW_PWRDN_CFG0);
+	udelay(1);
+
+	reg = readl_relaxed(clk_base + PLLU_BASE);
+	reg &= ~PLLU_BASE_CLKENABLE_USB;
+	writel_relaxed(reg, clk_base + PLLU_BASE);
+
+	reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
+	reg &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
+	writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+	udelay(10);
+
+	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2);
+
+	/* Program UTMIP PLL stable and active counts */
+	/* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */
+	reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+	reg |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
+
+	reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+
+	reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(utmi_parameters[i].
+					    active_delay_count);
+	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2);
+
+	/* Program UTMIP PLL delay and oscillator frequency counts */
+	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
+	reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+
+	reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(utmi_parameters[i].
+					    enable_delay_count);
+
+	reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+	reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(utmi_parameters[i].
+					   xtal_freq_count);
+
+	reg |= UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
+	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
+
+	/* Remove power downs from UTMIP PLL control bits */
+	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
+	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+	reg |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
+	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
+	udelay(1);
+
+	/* Enable samplers for SNPS, XUSB_HOST, XUSB_DEV */
+	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2);
+	reg |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERUP;
+	reg |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERUP;
+	reg |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERUP;
+	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+	reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERDOWN;
+	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2);
+
+	/* Setup HW control of UTMIPLL */
+	reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
+	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+	reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
+	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
+
+	reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
+	reg |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET;
+	reg &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL;
+	writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+	udelay(1);
+
+	reg = readl_relaxed(clk_base + XUSB_PLL_CFG0);
+	reg &= ~XUSB_PLL_CFG0_UTMIPLL_LOCK_DLY;
+	writel_relaxed(reg, clk_base + XUSB_PLL_CFG0);
+
+	udelay(1);
+
+	/* Enable HW control UTMIPLL */
+	reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
+	reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE;
+	writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
+}
+
+static __init void tegra210_periph_clk_init(void __iomem *clk_base,
+					    void __iomem *pmc_base)
+{
+	struct clk *clk;
+
+	/* xusb_ss_div2 */
+	clk = clk_register_fixed_factor(NULL, "xusb_ss_div2", "xusb_ss_src", 0,
+					1, 2);
+	clks[TEGRA210_CLK_XUSB_SS_DIV2] = clk;
+
+	/* pll_d_dsi_out */
+	clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0,
+				clk_base + PLLD_MISC0, 21, 0, &pll_d_lock);
+	clks[TEGRA210_CLK_PLL_D_DSI_OUT] = clk;
+
+	/* dsia */
+	clk = tegra_clk_register_periph_gate("dsia", "pll_d_dsi_out", 0,
+					     clk_base, 0, 48,
+					     periph_clk_enb_refcnt);
+	clks[TEGRA210_CLK_DSIA] = clk;
+
+	/* dsib */
+	clk = tegra_clk_register_periph_gate("dsib", "pll_d_dsi_out", 0,
+					     clk_base, 0, 82,
+					     periph_clk_enb_refcnt);
+	clks[TEGRA210_CLK_DSIB] = clk;
+
+	/* emc mux */
+	clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
+			       ARRAY_SIZE(mux_pllmcp_clkm), 0,
+			       clk_base + CLK_SOURCE_EMC,
+			       29, 3, 0, &emc_lock);
+
+	clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
+				    &emc_lock);
+	clks[TEGRA210_CLK_MC] = clk;
+
+	/* cml0 */
+	clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX,
+				0, 0, &pll_e_lock);
+	clk_register_clkdev(clk, "cml0", NULL);
+	clks[TEGRA210_CLK_CML0] = clk;
+
+	/* cml1 */
+	clk = clk_register_gate(NULL, "cml1", "pll_e", 0, clk_base + PLLE_AUX,
+				1, 0, &pll_e_lock);
+	clk_register_clkdev(clk, "cml1", NULL);
+	clks[TEGRA210_CLK_CML1] = clk;
+
+	tegra_periph_clk_init(clk_base, pmc_base, tegra210_clks, &pll_p_params);
+}
+
+static void __init tegra210_pll_init(void __iomem *clk_base,
+				     void __iomem *pmc)
+{
+	u32 val;
+	struct clk *clk;
+
+	/* PLLC */
+	clk = tegra_clk_register_pllxc_tegra210("pll_c", "pll_ref", clk_base,
+			pmc, 0, &pll_c_params, NULL);
+	if (!WARN_ON(IS_ERR(clk)))
+		clk_register_clkdev(clk, "pll_c", NULL);
+	clks[TEGRA210_CLK_PLL_C] = clk;
+
+	/* PLLC_OUT1 */
+	clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c",
+			clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP,
+			8, 8, 1, NULL);
+	clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div",
+				clk_base + PLLC_OUT, 1, 0,
+				CLK_SET_RATE_PARENT, 0, NULL);
+	clk_register_clkdev(clk, "pll_c_out1", NULL);
+	clks[TEGRA210_CLK_PLL_C_OUT1] = clk;
+
+	/* PLLC_UD */
+	clk = clk_register_fixed_factor(NULL, "pll_c_ud", "pll_c",
+					CLK_SET_RATE_PARENT, 1, 1);
+	clk_register_clkdev(clk, "pll_c_ud", NULL);
+	clks[TEGRA210_CLK_PLL_C_UD] = clk;
+
+	/* PLLC2 */
+	clk = tegra_clk_register_pllc_tegra210("pll_c2", "pll_ref", clk_base,
+			     pmc, 0, &pll_c2_params, NULL);
+	clk_register_clkdev(clk, "pll_c2", NULL);
+	clks[TEGRA210_CLK_PLL_C2] = clk;
+
+	/* PLLC3 */
+	clk = tegra_clk_register_pllc_tegra210("pll_c3", "pll_ref", clk_base,
+			     pmc, 0, &pll_c3_params, NULL);
+	clk_register_clkdev(clk, "pll_c3", NULL);
+	clks[TEGRA210_CLK_PLL_C3] = clk;
+
+	/* PLLM */
+	clk = tegra_clk_register_pllm("pll_m", "osc", clk_base, pmc,
+			     CLK_SET_RATE_GATE, &pll_m_params, NULL);
+	clk_register_clkdev(clk, "pll_m", NULL);
+	clks[TEGRA210_CLK_PLL_M] = clk;
+
+	/* PLLMB */
+	clk = tegra_clk_register_pllmb("pll_mb", "osc", clk_base, pmc,
+			     CLK_SET_RATE_GATE, &pll_mb_params, NULL);
+	clk_register_clkdev(clk, "pll_mb", NULL);
+	clks[TEGRA210_CLK_PLL_MB] = clk;
+
+	clk_register_clkdev(clk, "pll_m_out1", NULL);
+	clks[TEGRA210_CLK_PLL_M_OUT1] = clk;
+
+	/* PLLM_UD */
+	clk = clk_register_fixed_factor(NULL, "pll_m_ud", "pll_m",
+					CLK_SET_RATE_PARENT, 1, 1);
+	clk_register_clkdev(clk, "pll_m_ud", NULL);
+	clks[TEGRA210_CLK_PLL_M_UD] = clk;
+
+	/* PLLU_VCO */
+	val = readl(clk_base + pll_u_vco_params.base_reg);
+	val &= ~BIT(24); /* disable PLLU_OVERRIDE */
+	writel(val, clk_base + pll_u_vco_params.base_reg);
+
+	clk = tegra_clk_register_pllre("pll_u_vco", "pll_ref", clk_base, pmc,
+			    0, &pll_u_vco_params, &pll_u_lock, pll_ref_freq);
+	clk_register_clkdev(clk, "pll_u_vco", NULL);
+	clks[TEGRA210_CLK_PLL_U] = clk;
+
+	/* PLLU_OUT */
+	clk = clk_register_divider_table(NULL, "pll_u_out", "pll_u_vco", 0,
+					 clk_base + PLLU_BASE, 16, 4, 0,
+					 pll_vco_post_div_table, NULL);
+	clk_register_clkdev(clk, "pll_u_out", NULL);
+	clks[TEGRA210_CLK_PLL_U_OUT] = clk;
+
+	/* PLLU_OUT1 */
+	clk = tegra_clk_register_divider("pll_u_out1_div", "pll_u_out",
+				clk_base + PLLU_OUTA, 0,
+				TEGRA_DIVIDER_ROUND_UP,
+				8, 8, 1, &pll_u_lock);
+	clk = tegra_clk_register_pll_out("pll_u_out1", "pll_u_out1_div",
+				clk_base + PLLU_OUTA, 1, 0,
+				CLK_SET_RATE_PARENT, 0, &pll_u_lock);
+	clk_register_clkdev(clk, "pll_u_out1", NULL);
+	clks[TEGRA210_CLK_PLL_U_OUT1] = clk;
+
+	/* PLLU_OUT2 */
+	clk = tegra_clk_register_divider("pll_u_out2_div", "pll_u_out",
+				clk_base + PLLU_OUTA, 0,
+				TEGRA_DIVIDER_ROUND_UP,
+				24, 8, 1, &pll_u_lock);
+	clk = tegra_clk_register_pll_out("pll_u_out2", "pll_u_out2_div",
+				clk_base + PLLU_OUTA, 17, 16,
+				CLK_SET_RATE_PARENT, 0, &pll_u_lock);
+	clk_register_clkdev(clk, "pll_u_out2", NULL);
+	clks[TEGRA210_CLK_PLL_U_OUT2] = clk;
+
+	tegra210_utmi_param_configure(clk_base);
+
+	/* PLLU_480M */
+	clk = clk_register_gate(NULL, "pll_u_480M", "pll_u_vco",
+				CLK_SET_RATE_PARENT, clk_base + PLLU_BASE,
+				22, 0, &pll_u_lock);
+	clk_register_clkdev(clk, "pll_u_480M", NULL);
+	clks[TEGRA210_CLK_PLL_U_480M] = clk;
+
+	/* PLLU_60M */
+	clk = clk_register_gate(NULL, "pll_u_60M", "pll_u_out2",
+				CLK_SET_RATE_PARENT, clk_base + PLLU_BASE,
+				23, 0, NULL);
+	clk_register_clkdev(clk, "pll_u_60M", NULL);
+	clks[TEGRA210_CLK_PLL_U_60M] = clk;
+
+	/* PLLU_48M */
+	clk = clk_register_gate(NULL, "pll_u_48M", "pll_u_out1",
+				CLK_SET_RATE_PARENT, clk_base + PLLU_BASE,
+				25, 0, NULL);
+	clk_register_clkdev(clk, "pll_u_48M", NULL);
+	clks[TEGRA210_CLK_PLL_U_48M] = clk;
+
+	/* PLLD */
+	clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc, 0,
+			    &pll_d_params, &pll_d_lock);
+	clk_register_clkdev(clk, "pll_d", NULL);
+	clks[TEGRA210_CLK_PLL_D] = clk;
+
+	/* PLLD_OUT0 */
+	clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d",
+					CLK_SET_RATE_PARENT, 1, 2);
+	clk_register_clkdev(clk, "pll_d_out0", NULL);
+	clks[TEGRA210_CLK_PLL_D_OUT0] = clk;
+
+	/* PLLRE */
+	clk = tegra_clk_register_pllre("pll_re_vco", "pll_ref", clk_base, pmc,
+			     0, &pll_re_vco_params, &pll_re_lock, pll_ref_freq);
+	clk_register_clkdev(clk, "pll_re_vco", NULL);
+	clks[TEGRA210_CLK_PLL_RE_VCO] = clk;
+
+	clk = clk_register_divider_table(NULL, "pll_re_out", "pll_re_vco", 0,
+					 clk_base + PLLRE_BASE, 16, 5, 0,
+					 pll_vco_post_div_table, &pll_re_lock);
+	clk_register_clkdev(clk, "pll_re_out", NULL);
+	clks[TEGRA210_CLK_PLL_RE_OUT] = clk;
+
+	/* PLLE */
+	clk = tegra_clk_register_plle_tegra210("pll_e", "pll_ref",
+				      clk_base, 0, &pll_e_params, NULL);
+	clk_register_clkdev(clk, "pll_e", NULL);
+	clks[TEGRA210_CLK_PLL_E] = clk;
+
+	/* PLLC4 */
+	clk = tegra_clk_register_pllre("pll_c4_vco", "pll_ref", clk_base, pmc,
+			     0, &pll_c4_vco_params, NULL, pll_ref_freq);
+	clk_register_clkdev(clk, "pll_c4_vco", NULL);
+	clks[TEGRA210_CLK_PLL_C4] = clk;
+
+	/* PLLC4_OUT0 */
+	clk = clk_register_divider_table(NULL, "pll_c4_out0", "pll_c4_vco", 0,
+					 clk_base + PLLC4_BASE, 19, 4, 0,
+					 pll_vco_post_div_table, NULL);
+	clk_register_clkdev(clk, "pll_c4_out0", NULL);
+	clks[TEGRA210_CLK_PLL_C4_OUT0] = clk;
+
+	/* PLLC4_OUT1 */
+	clk = clk_register_fixed_factor(NULL, "pll_c4_out1", "pll_c4_vco",
+					CLK_SET_RATE_PARENT, 1, 3);
+	clk_register_clkdev(clk, "pll_c4_out1", NULL);
+	clks[TEGRA210_CLK_PLL_C4_OUT1] = clk;
+
+	/* PLLC4_OUT2 */
+	clk = clk_register_fixed_factor(NULL, "pll_c4_out2", "pll_c4_vco",
+					CLK_SET_RATE_PARENT, 1, 5);
+	clk_register_clkdev(clk, "pll_c4_out2", NULL);
+	clks[TEGRA210_CLK_PLL_C4_OUT2] = clk;
+
+	/* PLLC4_OUT3 */
+	clk = tegra_clk_register_divider("pll_c4_out3_div", "pll_c4_out0",
+			clk_base + PLLC4_OUT, 0, TEGRA_DIVIDER_ROUND_UP,
+			8, 8, 1, NULL);
+	clk = tegra_clk_register_pll_out("pll_c4_out3", "pll_c4_out3_div",
+				clk_base + PLLC4_OUT, 1, 0,
+				CLK_SET_RATE_PARENT, 0, NULL);
+	clk_register_clkdev(clk, "pll_c4_out3", NULL);
+	clks[TEGRA210_CLK_PLL_C4_OUT3] = clk;
+
+	/* PLLDP */
+	clk = tegra_clk_register_pllss_tegra210("pll_dp", "pll_ref", clk_base,
+					0, &pll_dp_params, NULL);
+	clk_register_clkdev(clk, "pll_dp", NULL);
+	clks[TEGRA210_CLK_PLL_DP] = clk;
+
+	/* PLLD2 */
+	clk = tegra_clk_register_pllss_tegra210("pll_d2", "pll_ref", clk_base,
+					0, &pll_d2_params, NULL);
+	clk_register_clkdev(clk, "pll_d2", NULL);
+	clks[TEGRA210_CLK_PLL_D2] = clk;
+
+	/* PLLD2_OUT0 */
+	clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2",
+					CLK_SET_RATE_PARENT, 1, 1);
+	clk_register_clkdev(clk, "pll_d2_out0", NULL);
+	clks[TEGRA210_CLK_PLL_D2_OUT0] = clk;
+
+	/* PLLP_OUT2 */
+	clk = clk_register_fixed_factor(NULL, "pll_p_out2", "pll_p",
+					CLK_SET_RATE_PARENT, 1, 2);
+	clk_register_clkdev(clk, "pll_p_out2", NULL);
+	clks[TEGRA210_CLK_PLL_P_OUT2] = clk;
+
+}
+
+/* Tegra210 CPU clock and reset control functions */
+static void tegra210_wait_cpu_in_reset(u32 cpu)
+{
+	unsigned int reg;
+
+	do {
+		reg = readl(clk_base + CLK_RST_CONTROLLER_CPU_CMPLX_STATUS);
+		cpu_relax();
+	} while (!(reg & (1 << cpu)));  /* check CPU been reset or not */
+}
+
+static void tegra210_disable_cpu_clock(u32 cpu)
+{
+	/* flow controller would take care in the power sequence. */
+}
+
+#ifdef CONFIG_PM_SLEEP
+static void tegra210_cpu_clock_suspend(void)
+{
+	/* switch coresite to clk_m, save off original source */
+	tegra210_cpu_clk_sctx.clk_csite_src =
+				readl(clk_base + CLK_SOURCE_CSITE);
+	writel(3 << 30, clk_base + CLK_SOURCE_CSITE);
+}
+
+static void tegra210_cpu_clock_resume(void)
+{
+	writel(tegra210_cpu_clk_sctx.clk_csite_src,
+				clk_base + CLK_SOURCE_CSITE);
+}
+#endif
+
+static struct tegra_cpu_car_ops tegra210_cpu_car_ops = {
+	.wait_for_reset	= tegra210_wait_cpu_in_reset,
+	.disable_clock	= tegra210_disable_cpu_clock,
+#ifdef CONFIG_PM_SLEEP
+	.suspend	= tegra210_cpu_clock_suspend,
+	.resume		= tegra210_cpu_clock_resume,
+#endif
+};
+
+static const struct of_device_id pmc_match[] __initconst = {
+	{ .compatible = "nvidia,tegra210-pmc" },
+	{ },
+};
+
+static struct tegra_clk_init_table init_table[] __initdata = {
+	{ TEGRA210_CLK_UARTA, TEGRA210_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA210_CLK_UARTB, TEGRA210_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA210_CLK_UARTC, TEGRA210_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA210_CLK_UARTD, TEGRA210_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA210_CLK_PLL_A, TEGRA210_CLK_CLK_MAX, 564480000, 1 },
+	{ TEGRA210_CLK_PLL_A_OUT0, TEGRA210_CLK_CLK_MAX, 11289600, 1 },
+	{ TEGRA210_CLK_EXTERN1, TEGRA210_CLK_PLL_A_OUT0, 0, 1 },
+	{ TEGRA210_CLK_CLK_OUT_1_MUX, TEGRA210_CLK_EXTERN1, 0, 1 },
+	{ TEGRA210_CLK_CLK_OUT_1, TEGRA210_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA210_CLK_I2S0, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA210_CLK_I2S1, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA210_CLK_I2S2, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA210_CLK_I2S3, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA210_CLK_I2S4, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA210_CLK_HOST1X, TEGRA210_CLK_PLL_P, 136000000, 1 },
+	{ TEGRA210_CLK_SCLK_MUX, TEGRA210_CLK_PLL_P, 0, 1 },
+	{ TEGRA210_CLK_SCLK, TEGRA210_CLK_CLK_MAX, 102000000, 1 },
+	{ TEGRA210_CLK_DFLL_SOC, TEGRA210_CLK_PLL_P, 51000000, 1 },
+	{ TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1 },
+	{ TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1 },
+	{ TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 672000000, 1 },
+	{ TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 },
+	{ TEGRA210_CLK_PLL_U_OUT2, TEGRA210_CLK_CLK_MAX, 60000000, 1 },
+	{ TEGRA210_CLK_XUSB_GATE, TEGRA210_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA210_CLK_XUSB_SS_SRC, TEGRA210_CLK_PLL_U_480M, 120000000, 0 },
+	{ TEGRA210_CLK_XUSB_FS_SRC, TEGRA210_CLK_PLL_U_48M, 48000000, 0 },
+	{ TEGRA210_CLK_XUSB_HS_SRC, TEGRA210_CLK_XUSB_SS_SRC, 120000000, 0 },
+	{ TEGRA210_CLK_XUSB_SSP_SRC, TEGRA210_CLK_XUSB_SS_SRC, 120000000, 0 },
+	{ TEGRA210_CLK_XUSB_FALCON_SRC, TEGRA210_CLK_PLL_P_OUT_XUSB, 204000000, 0 },
+	{ TEGRA210_CLK_XUSB_HOST_SRC, TEGRA210_CLK_PLL_P_OUT_XUSB, 102000000, 0 },
+	{ TEGRA210_CLK_XUSB_DEV_SRC, TEGRA210_CLK_PLL_P_OUT_XUSB, 102000000, 0 },
+	{ TEGRA210_CLK_SATA, TEGRA210_CLK_PLL_P, 104000000, 0 },
+	{ TEGRA210_CLK_SATA_OOB, TEGRA210_CLK_PLL_P, 204000000, 0 },
+	{ TEGRA210_CLK_EMC, TEGRA210_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA210_CLK_MSELECT, TEGRA210_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA210_CLK_CSITE, TEGRA210_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA210_CLK_TSENSOR, TEGRA210_CLK_CLK_M, 400000, 0 },
+	{ TEGRA210_CLK_I2C1, TEGRA210_CLK_PLL_P, 0, 0 },
+	{ TEGRA210_CLK_I2C2, TEGRA210_CLK_PLL_P, 0, 0 },
+	{ TEGRA210_CLK_I2C3, TEGRA210_CLK_PLL_P, 0, 0 },
+	{ TEGRA210_CLK_I2C4, TEGRA210_CLK_PLL_P, 0, 0 },
+	{ TEGRA210_CLK_I2C5, TEGRA210_CLK_PLL_P, 0, 0 },
+	{ TEGRA210_CLK_I2C6, TEGRA210_CLK_PLL_P, 0, 0 },
+	{ TEGRA210_CLK_PLL_DP, TEGRA210_CLK_CLK_MAX, 270000000, 0 },
+	{ TEGRA210_CLK_SOC_THERM, TEGRA210_CLK_PLL_P, 51000000, 0 },
+	{ TEGRA210_CLK_CCLK_G, TEGRA210_CLK_CLK_MAX, 0, 1 },
+	/* This MUST be the last entry. */
+	{ TEGRA210_CLK_CLK_MAX, TEGRA210_CLK_CLK_MAX, 0, 0 },
+};
+
+/**
+ * tegra210_clock_apply_init_table - initialize clocks on Tegra210 SoCs
+ *
+ * Program an initial clock rate and enable or disable clocks needed
+ * by the rest of the kernel, for Tegra210 SoCs.  It is intended to be
+ * called by assigning a pointer to it to tegra_clk_apply_init_table -
+ * this will be called as an arch_initcall.  No return value.
+ */
+static void __init tegra210_clock_apply_init_table(void)
+{
+	tegra_init_from_table(init_table, clks, TEGRA210_CLK_CLK_MAX);
+}
+
+/**
+ * tegra210_clock_init - Tegra210-specific clock initialization
+ * @np: struct device_node * of the DT node for the SoC CAR IP block
+ *
+ * Register most SoC clocks for the Tegra210 system-on-chip.  Intended
+ * to be called by the OF init code when a DT node with the
+ * "nvidia,tegra210-car" string is encountered, and declared with
+ * CLK_OF_DECLARE.  No return value.
+ */
+static void __init tegra210_clock_init(struct device_node *np)
+{
+	struct device_node *node;
+	u32 value, clk_m_div;
+
+	clk_base = of_iomap(np, 0);
+	if (!clk_base) {
+		pr_err("ioremap tegra210 CAR failed\n");
+		return;
+	}
+
+	node = of_find_matching_node(NULL, pmc_match);
+	if (!node) {
+		pr_err("Failed to find pmc node\n");
+		WARN_ON(1);
+		return;
+	}
+
+	pmc_base = of_iomap(node, 0);
+	if (!pmc_base) {
+		pr_err("Can't map pmc registers\n");
+		WARN_ON(1);
+		return;
+	}
+
+	clks = tegra_clk_init(clk_base, TEGRA210_CLK_CLK_MAX,
+			      TEGRA210_CAR_BANK_COUNT);
+	if (!clks)
+		return;
+
+	value = clk_readl(clk_base + SPARE_REG0) >> CLK_M_DIVISOR_SHIFT;
+	clk_m_div = (value & CLK_M_DIVISOR_MASK) + 1;
+
+	if (tegra_osc_clk_init(clk_base, tegra210_clks, tegra210_input_freq,
+			       ARRAY_SIZE(tegra210_input_freq), clk_m_div,
+			       &osc_freq, &pll_ref_freq) < 0)
+		return;
+
+	tegra_fixed_clk_init(tegra210_clks);
+	tegra210_pll_init(clk_base, pmc_base);
+	tegra210_periph_clk_init(clk_base, pmc_base);
+	tegra_audio_clk_init(clk_base, pmc_base, tegra210_clks,
+			     tegra210_audio_plls,
+			     ARRAY_SIZE(tegra210_audio_plls));
+	tegra_pmc_clk_init(pmc_base, tegra210_clks);
+
+	/* For Tegra210, PLLD is the only source for DSIA & DSIB */
+	value = clk_readl(clk_base + PLLD_BASE);
+	value &= ~BIT(25);
+	clk_writel(value, clk_base + PLLD_BASE);
+
+	tegra_clk_apply_init_table = tegra210_clock_apply_init_table;
+
+	tegra_super_clk_gen5_init(clk_base, pmc_base, tegra210_clks,
+				  &pll_x_params);
+	tegra_add_of_provider(np);
+	tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
+
+	tegra_cpu_car_ops = &tegra210_cpu_car_ops;
+}
+CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index b90db61..0478565 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -224,188 +224,192 @@
 };
 
 static const struct utmi_clk_param utmi_parameters[] = {
-/*	OSC_FREQUENCY, ENABLE_DLY, STABLE_CNT, ACTIVE_DLY, XTAL_FREQ_CNT */
-	{13000000,     0x02,       0x33,       0x05,       0x7F},
-	{19200000,     0x03,       0x4B,       0x06,       0xBB},
-	{12000000,     0x02,       0x2F,       0x04,       0x76},
-	{26000000,     0x04,       0x66,       0x09,       0xFE},
-	{16800000,     0x03,       0x41,       0x0A,       0xA4},
+	{
+		.osc_frequency = 13000000, .enable_delay_count = 0x02,
+		.stable_count = 0x33, .active_delay_count = 0x05,
+		.xtal_freq_count = 0x7f
+	}, {
+		.osc_frequency = 19200000, .enable_delay_count = 0x03,
+		.stable_count = 0x4b, .active_delay_count = 0x06,
+		.xtal_freq_count = 0xbb
+	}, {
+		.osc_frequency = 12000000, .enable_delay_count = 0x02,
+		.stable_count = 0x2f, .active_delay_count = 0x04,
+		.xtal_freq_count = 0x76
+	}, {
+		.osc_frequency = 26000000, .enable_delay_count = 0x04,
+		.stable_count = 0x66, .active_delay_count = 0x09,
+		.xtal_freq_count = 0xfe
+	}, {
+		.osc_frequency = 16800000, .enable_delay_count = 0x03,
+		.stable_count = 0x41, .active_delay_count = 0x0a,
+		.xtal_freq_count = 0xa4
+	},
 };
 
 static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
-	{ 12000000, 1040000000, 520,  6, 0, 8},
-	{ 13000000, 1040000000, 480,  6, 0, 8},
-	{ 16800000, 1040000000, 495,  8, 0, 8},	/* actual: 1039.5 MHz */
-	{ 19200000, 1040000000, 325,  6, 0, 6},
-	{ 26000000, 1040000000, 520, 13, 0, 8},
-
-	{ 12000000, 832000000, 416,  6, 0, 8},
-	{ 13000000, 832000000, 832, 13, 0, 8},
-	{ 16800000, 832000000, 396,  8, 0, 8},	/* actual: 831.6 MHz */
-	{ 19200000, 832000000, 260,  6, 0, 8},
-	{ 26000000, 832000000, 416, 13, 0, 8},
-
-	{ 12000000, 624000000, 624, 12, 0, 8},
-	{ 13000000, 624000000, 624, 13, 0, 8},
-	{ 16800000, 600000000, 520, 14, 0, 8},
-	{ 19200000, 624000000, 520, 16, 0, 8},
-	{ 26000000, 624000000, 624, 26, 0, 8},
-
-	{ 12000000, 600000000, 600, 12, 0, 8},
-	{ 13000000, 600000000, 600, 13, 0, 8},
-	{ 16800000, 600000000, 500, 14, 0, 8},
-	{ 19200000, 600000000, 375, 12, 0, 6},
-	{ 26000000, 600000000, 600, 26, 0, 8},
-
-	{ 12000000, 520000000, 520, 12, 0, 8},
-	{ 13000000, 520000000, 520, 13, 0, 8},
-	{ 16800000, 520000000, 495, 16, 0, 8},	/* actual: 519.75 MHz */
-	{ 19200000, 520000000, 325, 12, 0, 6},
-	{ 26000000, 520000000, 520, 26, 0, 8},
-
-	{ 12000000, 416000000, 416, 12, 0, 8},
-	{ 13000000, 416000000, 416, 13, 0, 8},
-	{ 16800000, 416000000, 396, 16, 0, 8},	/* actual: 415.8 MHz */
-	{ 19200000, 416000000, 260, 12, 0, 6},
-	{ 26000000, 416000000, 416, 26, 0, 8},
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000, 1040000000, 520,  6, 1, 8 },
+	{ 13000000, 1040000000, 480,  6, 1, 8 },
+	{ 16800000, 1040000000, 495,  8, 1, 8 }, /* actual: 1039.5 MHz */
+	{ 19200000, 1040000000, 325,  6, 1, 6 },
+	{ 26000000, 1040000000, 520, 13, 1, 8 },
+	{ 12000000,  832000000, 416,  6, 1, 8 },
+	{ 13000000,  832000000, 832, 13, 1, 8 },
+	{ 16800000,  832000000, 396,  8, 1, 8 }, /* actual: 831.6 MHz */
+	{ 19200000,  832000000, 260,  6, 1, 8 },
+	{ 26000000,  832000000, 416, 13, 1, 8 },
+	{ 12000000,  624000000, 624, 12, 1, 8 },
+	{ 13000000,  624000000, 624, 13, 1, 8 },
+	{ 16800000,  600000000, 520, 14, 1, 8 },
+	{ 19200000,  624000000, 520, 16, 1, 8 },
+	{ 26000000,  624000000, 624, 26, 1, 8 },
+	{ 12000000,  600000000, 600, 12, 1, 8 },
+	{ 13000000,  600000000, 600, 13, 1, 8 },
+	{ 16800000,  600000000, 500, 14, 1, 8 },
+	{ 19200000,  600000000, 375, 12, 1, 6 },
+	{ 26000000,  600000000, 600, 26, 1, 8 },
+	{ 12000000,  520000000, 520, 12, 1, 8 },
+	{ 13000000,  520000000, 520, 13, 1, 8 },
+	{ 16800000,  520000000, 495, 16, 1, 8 }, /* actual: 519.75 MHz */
+	{ 19200000,  520000000, 325, 12, 1, 6 },
+	{ 26000000,  520000000, 520, 26, 1, 8 },
+	{ 12000000,  416000000, 416, 12, 1, 8 },
+	{ 13000000,  416000000, 416, 13, 1, 8 },
+	{ 16800000,  416000000, 396, 16, 1, 8 }, /* actual: 415.8 MHz */
+	{ 19200000,  416000000, 260, 12, 1, 6 },
+	{ 26000000,  416000000, 416, 26, 1, 8 },
+	{        0,          0,   0,  0, 0, 0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
-	{ 12000000, 666000000, 666, 12, 0, 8},
-	{ 13000000, 666000000, 666, 13, 0, 8},
-	{ 16800000, 666000000, 555, 14, 0, 8},
-	{ 19200000, 666000000, 555, 16, 0, 8},
-	{ 26000000, 666000000, 666, 26, 0, 8},
-	{ 12000000, 600000000, 600, 12, 0, 8},
-	{ 13000000, 600000000, 600, 13, 0, 8},
-	{ 16800000, 600000000, 500, 14, 0, 8},
-	{ 19200000, 600000000, 375, 12, 0, 6},
-	{ 26000000, 600000000, 600, 26, 0, 8},
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000, 666000000, 666, 12, 1, 8 },
+	{ 13000000, 666000000, 666, 13, 1, 8 },
+	{ 16800000, 666000000, 555, 14, 1, 8 },
+	{ 19200000, 666000000, 555, 16, 1, 8 },
+	{ 26000000, 666000000, 666, 26, 1, 8 },
+	{ 12000000, 600000000, 600, 12, 1, 8 },
+	{ 13000000, 600000000, 600, 13, 1, 8 },
+	{ 16800000, 600000000, 500, 14, 1, 8 },
+	{ 19200000, 600000000, 375, 12, 1, 6 },
+	{ 26000000, 600000000, 600, 26, 1, 8 },
+	{        0,         0,   0,  0, 0, 0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
-	{ 12000000, 216000000, 432, 12, 1, 8},
-	{ 13000000, 216000000, 432, 13, 1, 8},
-	{ 16800000, 216000000, 360, 14, 1, 8},
-	{ 19200000, 216000000, 360, 16, 1, 8},
-	{ 26000000, 216000000, 432, 26, 1, 8},
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000, 216000000, 432, 12, 2, 8 },
+	{ 13000000, 216000000, 432, 13, 2, 8 },
+	{ 16800000, 216000000, 360, 14, 2, 8 },
+	{ 19200000, 216000000, 360, 16, 2, 8 },
+	{ 26000000, 216000000, 432, 26, 2, 8 },
+	{        0,         0,   0,  0, 0, 0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
-	{ 9600000, 564480000, 294, 5, 0, 4},
-	{ 9600000, 552960000, 288, 5, 0, 4},
-	{ 9600000, 24000000,  5,   2, 0, 1},
-
-	{ 28800000, 56448000, 49, 25, 0, 1},
-	{ 28800000, 73728000, 64, 25, 0, 1},
-	{ 28800000, 24000000,  5,  6, 0, 1},
-	{ 0, 0, 0, 0, 0, 0 },
+	{  9600000, 564480000, 294,  5, 1, 4 },
+	{  9600000, 552960000, 288,  5, 1, 4 },
+	{  9600000,  24000000,   5,  2, 1, 1 },
+	{ 28800000,  56448000,  49, 25, 1, 1 },
+	{ 28800000,  73728000,  64, 25, 1, 1 },
+	{ 28800000,  24000000,   5,  6, 1, 1 },
+	{        0,         0,   0,  0, 0, 0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
-	{ 12000000, 216000000, 216, 12, 0, 4},
-	{ 13000000, 216000000, 216, 13, 0, 4},
-	{ 16800000, 216000000, 180, 14, 0, 4},
-	{ 19200000, 216000000, 180, 16, 0, 4},
-	{ 26000000, 216000000, 216, 26, 0, 4},
-
-	{ 12000000, 594000000, 594, 12, 0, 8},
-	{ 13000000, 594000000, 594, 13, 0, 8},
-	{ 16800000, 594000000, 495, 14, 0, 8},
-	{ 19200000, 594000000, 495, 16, 0, 8},
-	{ 26000000, 594000000, 594, 26, 0, 8},
-
-	{ 12000000, 1000000000, 1000, 12, 0, 12},
-	{ 13000000, 1000000000, 1000, 13, 0, 12},
-	{ 19200000, 1000000000, 625,  12, 0, 8},
-	{ 26000000, 1000000000, 1000, 26, 0, 12},
-
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000,  216000000,  216, 12, 1,  4 },
+	{ 13000000,  216000000,  216, 13, 1,  4 },
+	{ 16800000,  216000000,  180, 14, 1,  4 },
+	{ 19200000,  216000000,  180, 16, 1,  4 },
+	{ 26000000,  216000000,  216, 26, 1,  4 },
+	{ 12000000,  594000000,  594, 12, 1,  8 },
+	{ 13000000,  594000000,  594, 13, 1,  8 },
+	{ 16800000,  594000000,  495, 14, 1,  8 },
+	{ 19200000,  594000000,  495, 16, 1,  8 },
+	{ 26000000,  594000000,  594, 26, 1,  8 },
+	{ 12000000, 1000000000, 1000, 12, 1, 12 },
+	{ 13000000, 1000000000, 1000, 13, 1, 12 },
+	{ 19200000, 1000000000,  625, 12, 1,  8 },
+	{ 26000000, 1000000000, 1000, 26, 1, 12 },
+	{        0,          0,    0,  0, 0,  0 },
 };
 
-static struct pdiv_map pllu_p[] = {
+static const struct pdiv_map pllu_p[] = {
 	{ .pdiv = 1, .hw_val = 1 },
 	{ .pdiv = 2, .hw_val = 0 },
 	{ .pdiv = 0, .hw_val = 0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
-	{ 12000000, 480000000, 960, 12, 0, 12},
-	{ 13000000, 480000000, 960, 13, 0, 12},
-	{ 16800000, 480000000, 400, 7,  0, 5},
-	{ 19200000, 480000000, 200, 4,  0, 3},
-	{ 26000000, 480000000, 960, 26, 0, 12},
-	{ 0, 0, 0, 0, 0, 0 },
+	{ 12000000, 480000000, 960, 12, 1, 12 },
+	{ 13000000, 480000000, 960, 13, 1, 12 },
+	{ 16800000, 480000000, 400,  7, 1,  5 },
+	{ 19200000, 480000000, 200,  4, 1,  3 },
+	{ 26000000, 480000000, 960, 26, 1, 12 },
+	{        0,         0,   0,  0, 0,  0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
 	/* 1.7 GHz */
-	{ 12000000, 1700000000, 850,  6,  0, 8},
-	{ 13000000, 1700000000, 915,  7,  0, 8},	/* actual: 1699.2 MHz */
-	{ 16800000, 1700000000, 708,  7,  0, 8},	/* actual: 1699.2 MHz */
-	{ 19200000, 1700000000, 885,  10, 0, 8},	/* actual: 1699.2 MHz */
-	{ 26000000, 1700000000, 850,  13, 0, 8},
-
+	{ 12000000, 1700000000, 850,   6, 1, 8 },
+	{ 13000000, 1700000000, 915,   7, 1, 8 }, /* actual: 1699.2 MHz */
+	{ 16800000, 1700000000, 708,   7, 1, 8 }, /* actual: 1699.2 MHz */
+	{ 19200000, 1700000000, 885,  10, 1, 8 }, /* actual: 1699.2 MHz */
+	{ 26000000, 1700000000, 850,  13, 1, 8 },
 	/* 1.6 GHz */
-	{ 12000000, 1600000000, 800,  6,  0, 8},
-	{ 13000000, 1600000000, 738,  6,  0, 8},	/* actual: 1599.0 MHz */
-	{ 16800000, 1600000000, 857,  9,  0, 8},	/* actual: 1599.7 MHz */
-	{ 19200000, 1600000000, 500,  6,  0, 8},
-	{ 26000000, 1600000000, 800,  13, 0, 8},
-
+	{ 12000000, 1600000000, 800,   6, 1, 8 },
+	{ 13000000, 1600000000, 738,   6, 1, 8 }, /* actual: 1599.0 MHz */
+	{ 16800000, 1600000000, 857,   9, 1, 8 }, /* actual: 1599.7 MHz */
+	{ 19200000, 1600000000, 500,   6, 1, 8 },
+	{ 26000000, 1600000000, 800,  13, 1, 8 },
 	/* 1.5 GHz */
-	{ 12000000, 1500000000, 750,  6,  0, 8},
-	{ 13000000, 1500000000, 923,  8,  0, 8},	/* actual: 1499.8 MHz */
-	{ 16800000, 1500000000, 625,  7,  0, 8},
-	{ 19200000, 1500000000, 625,  8,  0, 8},
-	{ 26000000, 1500000000, 750,  13, 0, 8},
-
+	{ 12000000, 1500000000, 750,   6, 1, 8 },
+	{ 13000000, 1500000000, 923,   8, 1, 8 }, /* actual: 1499.8 MHz */
+	{ 16800000, 1500000000, 625,   7, 1, 8 },
+	{ 19200000, 1500000000, 625,   8, 1, 8 },
+	{ 26000000, 1500000000, 750,  13, 1, 8 },
 	/* 1.4 GHz */
-	{ 12000000, 1400000000, 700,  6,  0, 8},
-	{ 13000000, 1400000000, 969,  9,  0, 8},	/* actual: 1399.7 MHz */
-	{ 16800000, 1400000000, 1000, 12, 0, 8},
-	{ 19200000, 1400000000, 875,  12, 0, 8},
-	{ 26000000, 1400000000, 700,  13, 0, 8},
-
+	{ 12000000, 1400000000,  700,  6, 1, 8 },
+	{ 13000000, 1400000000,  969,  9, 1, 8 }, /* actual: 1399.7 MHz */
+	{ 16800000, 1400000000, 1000, 12, 1, 8 },
+	{ 19200000, 1400000000,  875, 12, 1, 8 },
+	{ 26000000, 1400000000,  700, 13, 1, 8 },
 	/* 1.3 GHz */
-	{ 12000000, 1300000000, 975,  9,  0, 8},
-	{ 13000000, 1300000000, 1000, 10, 0, 8},
-	{ 16800000, 1300000000, 928,  12, 0, 8},	/* actual: 1299.2 MHz */
-	{ 19200000, 1300000000, 812,  12, 0, 8},	/* actual: 1299.2 MHz */
-	{ 26000000, 1300000000, 650,  13, 0, 8},
-
+	{ 12000000, 1300000000,  975,  9, 1, 8 },
+	{ 13000000, 1300000000, 1000, 10, 1, 8 },
+	{ 16800000, 1300000000,  928, 12, 1, 8 }, /* actual: 1299.2 MHz */
+	{ 19200000, 1300000000,  812, 12, 1, 8 }, /* actual: 1299.2 MHz */
+	{ 26000000, 1300000000,  650, 13, 1, 8 },
 	/* 1.2 GHz */
-	{ 12000000, 1200000000, 1000, 10, 0, 8},
-	{ 13000000, 1200000000, 923,  10, 0, 8},	/* actual: 1199.9 MHz */
-	{ 16800000, 1200000000, 1000, 14, 0, 8},
-	{ 19200000, 1200000000, 1000, 16, 0, 8},
-	{ 26000000, 1200000000, 600,  13, 0, 8},
-
+	{ 12000000, 1200000000, 1000, 10, 1, 8 },
+	{ 13000000, 1200000000,  923, 10, 1, 8 }, /* actual: 1199.9 MHz */
+	{ 16800000, 1200000000, 1000, 14, 1, 8 },
+	{ 19200000, 1200000000, 1000, 16, 1, 8 },
+	{ 26000000, 1200000000,  600, 13, 1, 8 },
 	/* 1.1 GHz */
-	{ 12000000, 1100000000, 825,  9,  0, 8},
-	{ 13000000, 1100000000, 846,  10, 0, 8},	/* actual: 1099.8 MHz */
-	{ 16800000, 1100000000, 982,  15, 0, 8},	/* actual: 1099.8 MHz */
-	{ 19200000, 1100000000, 859,  15, 0, 8},	/* actual: 1099.5 MHz */
-	{ 26000000, 1100000000, 550,  13, 0, 8},
-
+	{ 12000000, 1100000000, 825,   9, 1, 8 },
+	{ 13000000, 1100000000, 846,  10, 1, 8 }, /* actual: 1099.8 MHz */
+	{ 16800000, 1100000000, 982,  15, 1, 8 }, /* actual: 1099.8 MHz */
+	{ 19200000, 1100000000, 859,  15, 1, 8 }, /* actual: 1099.5 MHz */
+	{ 26000000, 1100000000, 550,  13, 1, 8 },
 	/* 1 GHz */
-	{ 12000000, 1000000000, 1000, 12, 0, 8},
-	{ 13000000, 1000000000, 1000, 13, 0, 8},
-	{ 16800000, 1000000000, 833,  14, 0, 8},	/* actual: 999.6 MHz */
-	{ 19200000, 1000000000, 625,  12, 0, 8},
-	{ 26000000, 1000000000, 1000, 26, 0, 8},
+	{ 12000000, 1000000000, 1000, 12, 1, 8 },
+	{ 13000000, 1000000000, 1000, 13, 1, 8 },
+	{ 16800000, 1000000000,  833, 14, 1, 8 }, /* actual: 999.6 MHz */
+	{ 19200000, 1000000000,  625, 12, 1, 8 },
+	{ 26000000, 1000000000, 1000, 26, 1, 8 },
+	{        0,          0,    0,  0, 0, 0 },
+};
 
-	{ 0, 0, 0, 0, 0, 0 },
+static const struct pdiv_map plle_p[] = {
+	{ .pdiv = 18, .hw_val = 18 },
+	{ .pdiv = 24, .hw_val = 24 },
+	{ .pdiv =  0, .hw_val =  0 },
 };
 
 static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
 	/* PLLE special case: use cpcon field to store cml divider value */
-	{ 12000000,  100000000, 150, 1,  18, 11},
-	{ 216000000, 100000000, 200, 18, 24, 13},
-	{ 0, 0, 0, 0, 0, 0 },
+	{  12000000, 100000000, 150,  1, 18, 11 },
+	{ 216000000, 100000000, 200, 18, 24, 13 },
+	{         0,         0,   0,  0,  0,  0 },
 };
 
 /* PLL parameters */
@@ -422,7 +426,8 @@
 	.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
 	.lock_delay = 300,
 	.freq_table = pll_c_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
+		 TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct div_nmp pllm_nmp = {
@@ -454,7 +459,8 @@
 	.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE,
 	.freq_table = pll_m_freq_table,
 	.flags = TEGRA_PLLM | TEGRA_PLL_HAS_CPCON |
-		 TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK,
+		 TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK |
+		 TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_FIXED,
 };
 
 static struct tegra_clk_pll_params pll_p_params = {
@@ -470,7 +476,8 @@
 	.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
 	.lock_delay = 300,
 	.freq_table = pll_p_freq_table,
-	.flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
+		 TEGRA_PLL_HAS_LOCK_ENABLE,
 	.fixed_rate = 408000000,
 };
 
@@ -487,7 +494,8 @@
 	.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
 	.lock_delay = 300,
 	.freq_table = pll_a_freq_table,
-	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
+		 TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_params pll_d_params = {
@@ -504,8 +512,7 @@
 	.lock_delay = 1000,
 	.freq_table = pll_d_freq_table,
 	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
-
+		 TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_params pll_d2_params = {
@@ -522,7 +529,7 @@
 	.lock_delay = 1000,
 	.freq_table = pll_d_freq_table,
 	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
-		 TEGRA_PLL_USE_LOCK,
+		 TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_params pll_u_params = {
@@ -539,7 +546,8 @@
 	.lock_delay = 1000,
 	.pdiv_tohw = pllu_p,
 	.freq_table = pll_u_freq_table,
-	.flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON,
+	.flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
+		 TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_params pll_x_params = {
@@ -556,7 +564,7 @@
 	.lock_delay = 300,
 	.freq_table = pll_x_freq_table,
 	.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_DCCON |
-		 TEGRA_PLL_USE_LOCK,
+		 TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
 };
 
 static struct tegra_clk_pll_params pll_e_params = {
@@ -571,19 +579,21 @@
 	.lock_mask = PLLE_MISC_LOCK,
 	.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
 	.lock_delay = 300,
+	.pdiv_tohw = plle_p,
 	.freq_table = pll_e_freq_table,
-	.flags = TEGRA_PLLE_CONFIGURE | TEGRA_PLL_FIXED,
+	.flags = TEGRA_PLLE_CONFIGURE | TEGRA_PLL_FIXED |
+		 TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_LOCK_MISC,
 	.fixed_rate = 100000000,
 };
 
 static unsigned long tegra30_input_freq[] = {
-	[0] = 13000000,
-	[1] = 16800000,
-	[4] = 19200000,
-	[5] = 38400000,
-	[8] = 12000000,
-	[9] = 48000000,
-	[12] = 260000000,
+	[ 0] = 13000000,
+	[ 1] = 16800000,
+	[ 4] = 19200000,
+	[ 5] = 38400000,
+	[ 8] = 12000000,
+	[ 9] = 48000000,
+	[12] = 26000000,
 };
 
 static struct tegra_devclk devclks[] __initdata = {
@@ -861,13 +871,12 @@
 	[tegra_clk_pll_p_out4] = { .dt_id = TEGRA30_CLK_PLL_P_OUT4, .present = true },
 	[tegra_clk_pll_a] = { .dt_id = TEGRA30_CLK_PLL_A, .present = true },
 	[tegra_clk_pll_a_out0] = { .dt_id = TEGRA30_CLK_PLL_A_OUT0, .present = true },
-
 };
 
 static void tegra30_utmi_param_configure(void)
 {
+	unsigned int i;
 	u32 reg;
-	int i;
 
 	for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
 		if (input_freq == utmi_parameters[i].osc_frequency)
@@ -917,7 +926,7 @@
 	writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
 }
 
-static const char *pll_e_parents[] = {"pll_ref", "pll_p"};
+static const char *pll_e_parents[] = { "pll_ref", "pll_p" };
 
 static void __init tegra30_pll_init(void)
 {
@@ -925,7 +934,7 @@
 
 	/* PLLC */
 	clk = tegra_clk_register_pll("pll_c", "pll_ref", clk_base, pmc_base, 0,
-				&pll_c_params, NULL);
+				     &pll_c_params, NULL);
 	clks[TEGRA30_CLK_PLL_C] = clk;
 
 	/* PLLC_OUT1 */
@@ -1135,7 +1144,7 @@
 {
 	struct tegra_periph_init_data *data;
 	struct clk *clk;
-	int i;
+	unsigned int i;
 
 	/* dsia */
 	clk = tegra_clk_register_periph_gate("dsia", "pll_d_out0", 0, clk_base,
@@ -1224,7 +1233,6 @@
 	wmb();
 }
 
-
 static void tegra30_enable_cpu_clock(u32 cpu)
 {
 	unsigned int reg;
@@ -1237,7 +1245,6 @@
 
 static void tegra30_disable_cpu_clock(u32 cpu)
 {
-
 	unsigned int reg;
 
 	reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
@@ -1268,7 +1275,7 @@
 	/* switch coresite to clk_m, save off original source */
 	tegra30_cpu_clk_sctx.clk_csite_src =
 				readl(clk_base + CLK_RESET_SOURCE_CSITE);
-	writel(3<<30, clk_base + CLK_RESET_SOURCE_CSITE);
+	writel(3 << 30, clk_base + CLK_RESET_SOURCE_CSITE);
 
 	tegra30_cpu_clk_sctx.cpu_burst =
 				readl(clk_base + CLK_RESET_CCLK_BURST);
@@ -1335,44 +1342,45 @@
 };
 
 static struct tegra_clk_init_table init_table[] __initdata = {
-	{TEGRA30_CLK_UARTA, TEGRA30_CLK_PLL_P, 408000000, 0},
-	{TEGRA30_CLK_UARTB, TEGRA30_CLK_PLL_P, 408000000, 0},
-	{TEGRA30_CLK_UARTC, TEGRA30_CLK_PLL_P, 408000000, 0},
-	{TEGRA30_CLK_UARTD, TEGRA30_CLK_PLL_P, 408000000, 0},
-	{TEGRA30_CLK_UARTE, TEGRA30_CLK_PLL_P, 408000000, 0},
-	{TEGRA30_CLK_PLL_A, TEGRA30_CLK_CLK_MAX, 564480000, 1},
-	{TEGRA30_CLK_PLL_A_OUT0, TEGRA30_CLK_CLK_MAX, 11289600, 1},
-	{TEGRA30_CLK_EXTERN1, TEGRA30_CLK_PLL_A_OUT0, 0, 1},
-	{TEGRA30_CLK_CLK_OUT_1_MUX, TEGRA30_CLK_EXTERN1, 0, 0},
-	{TEGRA30_CLK_CLK_OUT_1, TEGRA30_CLK_CLK_MAX, 0, 1},
-	{TEGRA30_CLK_BLINK, TEGRA30_CLK_CLK_MAX, 0, 1},
-	{TEGRA30_CLK_I2S0, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA30_CLK_I2S1, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA30_CLK_I2S2, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA30_CLK_I2S3, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA30_CLK_I2S4, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0},
-	{TEGRA30_CLK_SDMMC1, TEGRA30_CLK_PLL_P, 48000000, 0},
-	{TEGRA30_CLK_SDMMC2, TEGRA30_CLK_PLL_P, 48000000, 0},
-	{TEGRA30_CLK_SDMMC3, TEGRA30_CLK_PLL_P, 48000000, 0},
-	{TEGRA30_CLK_PLL_M, TEGRA30_CLK_CLK_MAX, 0, 1},
-	{TEGRA30_CLK_PCLK, TEGRA30_CLK_CLK_MAX, 0, 1},
-	{TEGRA30_CLK_CSITE, TEGRA30_CLK_CLK_MAX, 0, 1},
-	{TEGRA30_CLK_EMC, TEGRA30_CLK_CLK_MAX, 0, 1},
-	{TEGRA30_CLK_MSELECT, TEGRA30_CLK_CLK_MAX, 0, 1},
-	{TEGRA30_CLK_SBC1, TEGRA30_CLK_PLL_P, 100000000, 0},
-	{TEGRA30_CLK_SBC2, TEGRA30_CLK_PLL_P, 100000000, 0},
-	{TEGRA30_CLK_SBC3, TEGRA30_CLK_PLL_P, 100000000, 0},
-	{TEGRA30_CLK_SBC4, TEGRA30_CLK_PLL_P, 100000000, 0},
-	{TEGRA30_CLK_SBC5, TEGRA30_CLK_PLL_P, 100000000, 0},
-	{TEGRA30_CLK_SBC6, TEGRA30_CLK_PLL_P, 100000000, 0},
-	{TEGRA30_CLK_HOST1X, TEGRA30_CLK_PLL_C, 150000000, 0},
-	{TEGRA30_CLK_DISP1, TEGRA30_CLK_PLL_P, 600000000, 0},
-	{TEGRA30_CLK_DISP2, TEGRA30_CLK_PLL_P, 600000000, 0},
-	{TEGRA30_CLK_TWD, TEGRA30_CLK_CLK_MAX, 0, 1},
-	{TEGRA30_CLK_GR2D, TEGRA30_CLK_PLL_C, 300000000, 0},
-	{TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0},
-	{TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0},
-	{TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0}, /* This MUST be the last entry. */
+	{ TEGRA30_CLK_UARTA, TEGRA30_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA30_CLK_UARTB, TEGRA30_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA30_CLK_UARTC, TEGRA30_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA30_CLK_UARTD, TEGRA30_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA30_CLK_UARTE, TEGRA30_CLK_PLL_P, 408000000, 0 },
+	{ TEGRA30_CLK_PLL_A, TEGRA30_CLK_CLK_MAX, 564480000, 1 },
+	{ TEGRA30_CLK_PLL_A_OUT0, TEGRA30_CLK_CLK_MAX, 11289600, 1 },
+	{ TEGRA30_CLK_EXTERN1, TEGRA30_CLK_PLL_A_OUT0, 0, 1 },
+	{ TEGRA30_CLK_CLK_OUT_1_MUX, TEGRA30_CLK_EXTERN1, 0, 0 },
+	{ TEGRA30_CLK_CLK_OUT_1, TEGRA30_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA30_CLK_BLINK, TEGRA30_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA30_CLK_I2S0, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA30_CLK_I2S1, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA30_CLK_I2S2, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA30_CLK_I2S3, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA30_CLK_I2S4, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 },
+	{ TEGRA30_CLK_SDMMC1, TEGRA30_CLK_PLL_P, 48000000, 0 },
+	{ TEGRA30_CLK_SDMMC2, TEGRA30_CLK_PLL_P, 48000000, 0 },
+	{ TEGRA30_CLK_SDMMC3, TEGRA30_CLK_PLL_P, 48000000, 0 },
+	{ TEGRA30_CLK_PLL_M, TEGRA30_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA30_CLK_PCLK, TEGRA30_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA30_CLK_CSITE, TEGRA30_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA30_CLK_EMC, TEGRA30_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA30_CLK_MSELECT, TEGRA30_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA30_CLK_SBC1, TEGRA30_CLK_PLL_P, 100000000, 0 },
+	{ TEGRA30_CLK_SBC2, TEGRA30_CLK_PLL_P, 100000000, 0 },
+	{ TEGRA30_CLK_SBC3, TEGRA30_CLK_PLL_P, 100000000, 0 },
+	{ TEGRA30_CLK_SBC4, TEGRA30_CLK_PLL_P, 100000000, 0 },
+	{ TEGRA30_CLK_SBC5, TEGRA30_CLK_PLL_P, 100000000, 0 },
+	{ TEGRA30_CLK_SBC6, TEGRA30_CLK_PLL_P, 100000000, 0 },
+	{ TEGRA30_CLK_HOST1X, TEGRA30_CLK_PLL_C, 150000000, 0 },
+	{ TEGRA30_CLK_DISP1, TEGRA30_CLK_PLL_P, 600000000, 0 },
+	{ TEGRA30_CLK_DISP2, TEGRA30_CLK_PLL_P, 600000000, 0 },
+	{ TEGRA30_CLK_TWD, TEGRA30_CLK_CLK_MAX, 0, 1 },
+	{ TEGRA30_CLK_GR2D, TEGRA30_CLK_PLL_C, 300000000, 0 },
+	{ TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0 },
+	{ TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0 },
+	/* must be the last entry */
+	{ TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
 };
 
 static void __init tegra30_clock_apply_init_table(void)
@@ -1397,12 +1405,13 @@
 	TEGRA_CLK_DUPLICATE(TEGRA30_CLK_CML1, "tegra_sata_cml", NULL),
 	TEGRA_CLK_DUPLICATE(TEGRA30_CLK_CML0, "tegra_pcie", "cml"),
 	TEGRA_CLK_DUPLICATE(TEGRA30_CLK_VCP, "nvavp", "vcp"),
-	TEGRA_CLK_DUPLICATE(TEGRA30_CLK_CLK_MAX, NULL, NULL), /* MUST be the last entry */
+	/* must be the last entry */
+	TEGRA_CLK_DUPLICATE(TEGRA30_CLK_CLK_MAX, NULL, NULL),
 };
 
 static const struct of_device_id pmc_match[] __initconst = {
 	{ .compatible = "nvidia,tegra30-pmc" },
-	{},
+	{ },
 };
 
 static struct tegra_audio_clk_info tegra30_audio_plls[] = {
@@ -1441,7 +1450,6 @@
 			       NULL) < 0)
 		return;
 
-
 	tegra_fixed_clk_init(tegra30_clks);
 	tegra30_pll_init();
 	tegra30_super_clk_init();
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 5d26789..4dbcfae 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -110,14 +110,16 @@
  * @m:			input divider
  * @p:			post divider
  * @cpcon:		charge pump current
+ * @sdm_data:		fraction divider setting (0 = disabled)
  */
 struct tegra_clk_pll_freq_table {
 	unsigned long	input_rate;
 	unsigned long	output_rate;
-	u16		n;
+	u32		n;
 	u16		m;
 	u8		p;
 	u8		cpcon;
+	u16		sdm_data;
 };
 
 /**
@@ -156,6 +158,10 @@
 	u8		override_divp_shift;
 };
 
+#define MAX_PLL_MISC_REG_COUNT	6
+
+struct tegra_clk_pll;
+
 /**
  * struct tegra_clk_pll_params - PLL parameters
  *
@@ -172,6 +178,14 @@
  * @lock_enable_bit_idx:	Bit index to enable PLL lock
  * @iddq_reg:			PLL IDDQ register offset
  * @iddq_bit_idx:		Bit index to enable PLL IDDQ
+ * @reset_reg:			Register offset of where RESET bit is
+ * @reset_bit_idx:		Shift of reset bit in reset_reg
+ * @sdm_din_reg:		Register offset where SDM settings are
+ * @sdm_din_mask:		Mask of SDM divider bits
+ * @sdm_ctrl_reg:		Register offset where SDM enable is
+ * @sdm_ctrl_en_mask:		Mask of SDM enable bit
+ * @ssc_ctrl_reg:		Register offset where SSC settings are
+ * @ssc_ctrl_en_mask:		Mask of SSC enable bit
  * @aux_reg:			AUX register offset
  * @dyn_ramp_reg:		Dynamic ramp control register offset
  * @ext_misc_reg:		Miscellaneous control register offsets
@@ -182,10 +196,27 @@
  * @stepb_shift:		Dynamic ramp step B field shift
  * @lock_delay:			Delay in us if PLL lock is not used
  * @max_p:			maximum value for the p divider
+ * @defaults_set:		Boolean signaling all reg defaults for PLL set.
  * @pdiv_tohw:			mapping of p divider to register values
  * @div_nmp:			offsets and widths on n, m and p fields
  * @freq_table:			array of frequencies supported by PLL
  * @fixed_rate:			PLL rate if it is fixed
+ * @mdiv_default:		Default value for fixed mdiv for this PLL
+ * @round_p_to_pdiv:		Callback used to round p to the closed pdiv
+ * @set_gain:			Callback to adjust N div for SDM enabled
+ *				PLL's based on fractional divider value.
+ * @calc_rate:			Callback used to change how out of table
+ *				rates (dividers and multipler) are calculated.
+ * @adjust_vco:			Callback to adjust the programming range of the
+ *				divider range (if SDM is present)
+ * @set_defaults:		Callback which will try to initialize PLL
+ *				registers to sane default values. This is first
+ *				tried during PLL registration, but if the PLL
+ *				is already enabled, it will be done the first
+ *				time the rate is changed while the PLL is
+ *				disabled.
+ * @dyn_ramp:			Callback which can be used to define a custom
+ *				dynamic ramp function for a given PLL.
  *
  * Flags:
  * TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for
@@ -207,6 +238,11 @@
  *     base register.
  * TEGRA_PLL_BYPASS - PLL has bypass bit
  * TEGRA_PLL_HAS_LOCK_ENABLE - PLL has bit to enable lock monitoring
+ * TEGRA_MDIV_NEW - Switch to new method for calculating fixed mdiv
+ *     it may be more accurate (especially if SDM present)
+ * TEGRA_PLLMB - PLLMB has should be treated similar to PLLM. This
+ *     flag indicated that it is PLLMB.
+ * TEGRA_PLL_VCO_OUT - Used to indicate that the PLL has a VCO output
  */
 struct tegra_clk_pll_params {
 	unsigned long	input_min;
@@ -223,9 +259,17 @@
 	u32		lock_enable_bit_idx;
 	u32		iddq_reg;
 	u32		iddq_bit_idx;
+	u32		reset_reg;
+	u32		reset_bit_idx;
+	u32		sdm_din_reg;
+	u32		sdm_din_mask;
+	u32		sdm_ctrl_reg;
+	u32		sdm_ctrl_en_mask;
+	u32		ssc_ctrl_reg;
+	u32		ssc_ctrl_en_mask;
 	u32		aux_reg;
 	u32		dyn_ramp_reg;
-	u32		ext_misc_reg[3];
+	u32		ext_misc_reg[MAX_PLL_MISC_REG_COUNT];
 	u32		pmc_divnm_reg;
 	u32		pmc_divp_reg;
 	u32		flags;
@@ -233,10 +277,22 @@
 	int		stepb_shift;
 	int		lock_delay;
 	int		max_p;
-	struct pdiv_map *pdiv_tohw;
+	bool		defaults_set;
+	const struct pdiv_map *pdiv_tohw;
 	struct div_nmp	*div_nmp;
 	struct tegra_clk_pll_freq_table	*freq_table;
 	unsigned long	fixed_rate;
+	u16		mdiv_default;
+	u32	(*round_p_to_pdiv)(u32 p, u32 *pdiv);
+	void	(*set_gain)(struct tegra_clk_pll_freq_table *cfg);
+	int	(*calc_rate)(struct clk_hw *hw,
+			struct tegra_clk_pll_freq_table *cfg,
+			unsigned long rate, unsigned long parent_rate);
+	unsigned long	(*adjust_vco)(struct tegra_clk_pll_params *pll_params,
+				unsigned long parent_rate);
+	void	(*set_defaults)(struct tegra_clk_pll *pll);
+	int	(*dyn_ramp)(struct tegra_clk_pll *pll,
+			struct tegra_clk_pll_freq_table *cfg);
 };
 
 #define TEGRA_PLL_USE_LOCK BIT(0)
@@ -250,6 +306,9 @@
 #define TEGRA_PLL_LOCK_MISC BIT(8)
 #define TEGRA_PLL_BYPASS BIT(9)
 #define TEGRA_PLL_HAS_LOCK_ENABLE BIT(10)
+#define TEGRA_MDIV_NEW BIT(11)
+#define TEGRA_PLLMB BIT(12)
+#define TEGRA_PLL_VCO_OUT BIT(13)
 
 /**
  * struct tegra_clk_pll - Tegra PLL clock
@@ -303,6 +362,12 @@
 			    struct tegra_clk_pll_params *pll_params,
 			    spinlock_t *lock);
 
+struct clk *tegra_clk_register_pllxc_tegra210(const char *name,
+			const char *parent_name, void __iomem *clk_base,
+			void __iomem *pmc, unsigned long flags,
+			struct tegra_clk_pll_params *pll_params,
+			spinlock_t *lock);
+
 struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
 			   void __iomem *clk_base, void __iomem *pmc,
 			   unsigned long flags,
@@ -327,11 +392,35 @@
 				struct tegra_clk_pll_params *pll_params,
 				spinlock_t *lock);
 
+struct clk *tegra_clk_register_plle_tegra210(const char *name,
+				const char *parent_name,
+				void __iomem *clk_base, unsigned long flags,
+				struct tegra_clk_pll_params *pll_params,
+				spinlock_t *lock);
+
+struct clk *tegra_clk_register_pllc_tegra210(const char *name,
+				const char *parent_name, void __iomem *clk_base,
+				void __iomem *pmc, unsigned long flags,
+				struct tegra_clk_pll_params *pll_params,
+				spinlock_t *lock);
+
+struct clk *tegra_clk_register_pllss_tegra210(const char *name,
+				const char *parent_name, void __iomem *clk_base,
+				unsigned long flags,
+				struct tegra_clk_pll_params *pll_params,
+				spinlock_t *lock);
+
 struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
 			   void __iomem *clk_base, unsigned long flags,
 			   struct tegra_clk_pll_params *pll_params,
 			   spinlock_t *lock);
 
+struct clk *tegra_clk_register_pllmb(const char *name, const char *parent_name,
+			   void __iomem *clk_base, void __iomem *pmc,
+			   unsigned long flags,
+			   struct tegra_clk_pll_params *pll_params,
+			   spinlock_t *lock);
+
 /**
  * struct tegra_clk_pll_out - PLL divider down clock
  *
@@ -653,6 +742,9 @@
 void tegra_super_clk_gen4_init(void __iomem *clk_base,
 			void __iomem *pmc_base, struct tegra_clk *tegra_clks,
 			struct tegra_clk_pll_params *pll_params);
+void tegra_super_clk_gen5_init(void __iomem *clk_base,
+			void __iomem *pmc_base, struct tegra_clk *tegra_clks,
+			struct tegra_clk_pll_params *pll_params);
 
 #ifdef CONFIG_TEGRA_CLK_EMC
 struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np,
@@ -674,5 +766,8 @@
 
 typedef void (*tegra_clk_apply_init_table_func)(void);
 extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
+int tegra_pll_wait_for_lock(struct tegra_clk_pll *pll);
+u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate);
+int tegra_pll_p_div_to_hw(struct tegra_clk_pll *pll, u8 p_div);
 
 #endif /* TEGRA_CLK_H */
diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c
index f3eab6e..b336a8c 100644
--- a/drivers/clk/ti/apll.c
+++ b/drivers/clk/ti/apll.c
@@ -323,7 +323,7 @@
 	omap2_apll_set_autoidle(clk, OMAP2_APLL_AUTOIDLE_DISABLE);
 }
 
-static struct clk_hw_omap_ops omap2_apll_hwops = {
+static const struct clk_hw_omap_ops omap2_apll_hwops = {
 	.allow_idle	= &omap2_apll_allow_idle,
 	.deny_idle	= &omap2_apll_deny_idle,
 };
diff --git a/drivers/clk/ti/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c
index f4dec00..1c30038 100644
--- a/drivers/clk/ti/dpll3xxx.c
+++ b/drivers/clk/ti/dpll3xxx.c
@@ -305,8 +305,9 @@
 static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
 {
 	struct dpll_data *dd = clk->dpll_data;
-	u8 dco, sd_div;
+	u8 dco, sd_div, ai = 0;
 	u32 v;
+	bool errata_i810;
 
 	/* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */
 	_omap3_noncore_dpll_bypass(clk);
@@ -350,6 +351,25 @@
 		v |= sd_div << __ffs(dd->sddiv_mask);
 	}
 
+	/*
+	 * Errata i810 - DPLL controller can get stuck while transitioning
+	 * to a power saving state. Software must ensure the DPLL can not
+	 * transition to a low power state while changing M/N values.
+	 * Easiest way to accomplish this is to prevent DPLL autoidle
+	 * before doing the M/N re-program.
+	 */
+	errata_i810 = ti_clk_get_features()->flags & TI_CLK_ERRATA_I810;
+
+	if (errata_i810) {
+		ai = omap3_dpll_autoidle_read(clk);
+		if (ai) {
+			omap3_dpll_deny_idle(clk);
+
+			/* OCP barrier */
+			omap3_dpll_autoidle_read(clk);
+		}
+	}
+
 	ti_clk_ll_ops->clk_writel(v, dd->mult_div1_reg);
 
 	/* Set 4X multiplier and low-power mode */
@@ -379,6 +399,9 @@
 
 	_omap3_noncore_dpll_lock(clk);
 
+	if (errata_i810 && ai)
+		omap3_dpll_allow_idle(clk);
+
 	return 0;
 }
 
diff --git a/drivers/clk/versatile/clk-sp810.c b/drivers/clk/versatile/clk-sp810.c
index a1cdef6..e78755e 100644
--- a/drivers/clk/versatile/clk-sp810.c
+++ b/drivers/clk/versatile/clk-sp810.c
@@ -95,13 +95,12 @@
 	int i;
 	bool deprecated;
 
-	if (!sp810) {
-		pr_err("Failed to allocate memory for SP810!\n");
+	if (!sp810)
 		return;
-	}
 
 	if (of_clk_parent_fill(node, parent_names, num) != num) {
 		pr_warn("Failed to obtain parent clocks for SP810!\n");
+		kfree(sp810);
 		return;
 	}
 
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 3a8ce67..79b1390 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -444,7 +444,7 @@
 	  here.
 
 config S3C24XX_DMAC
-	tristate "Samsung S3C24XX DMA support"
+	bool "Samsung S3C24XX DMA support"
 	depends on ARCH_S3C24XX
 	select DMA_ENGINE
 	select DMA_VIRTUAL_CHANNELS
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 0e08e66..88bebe1 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -321,39 +321,58 @@
 	list_add_tail(&dev->list, &dmi_devices);
 }
 
-static void __init dmi_save_dev_onboard(int instance, int segment, int bus,
-					int devfn, const char *name)
+static void __init dmi_save_dev_pciaddr(int instance, int segment, int bus,
+					int devfn, const char *name, int type)
 {
-	struct dmi_dev_onboard *onboard_dev;
+	struct dmi_dev_onboard *dev;
 
-	onboard_dev = dmi_alloc(sizeof(*onboard_dev) + strlen(name) + 1);
-	if (!onboard_dev)
+	/* Ignore invalid values */
+	if (type == DMI_DEV_TYPE_DEV_SLOT &&
+	    segment == 0xFFFF && bus == 0xFF && devfn == 0xFF)
 		return;
 
-	onboard_dev->instance = instance;
-	onboard_dev->segment = segment;
-	onboard_dev->bus = bus;
-	onboard_dev->devfn = devfn;
+	dev = dmi_alloc(sizeof(*dev) + strlen(name) + 1);
+	if (!dev)
+		return;
 
-	strcpy((char *)&onboard_dev[1], name);
-	onboard_dev->dev.type = DMI_DEV_TYPE_DEV_ONBOARD;
-	onboard_dev->dev.name = (char *)&onboard_dev[1];
-	onboard_dev->dev.device_data = onboard_dev;
+	dev->instance = instance;
+	dev->segment = segment;
+	dev->bus = bus;
+	dev->devfn = devfn;
 
-	list_add(&onboard_dev->dev.list, &dmi_devices);
+	strcpy((char *)&dev[1], name);
+	dev->dev.type = type;
+	dev->dev.name = (char *)&dev[1];
+	dev->dev.device_data = dev;
+
+	list_add(&dev->dev.list, &dmi_devices);
 }
 
 static void __init dmi_save_extended_devices(const struct dmi_header *dm)
 {
-	const u8 *d = (u8 *) dm + 5;
+	const char *name;
+	const u8 *d = (u8 *)dm;
 
 	/* Skip disabled device */
-	if ((*d & 0x80) == 0)
+	if ((d[0x5] & 0x80) == 0)
 		return;
 
-	dmi_save_dev_onboard(*(d+1), *(u16 *)(d+2), *(d+4), *(d+5),
-			     dmi_string_nosave(dm, *(d-1)));
-	dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1)));
+	name = dmi_string_nosave(dm, d[0x4]);
+	dmi_save_dev_pciaddr(d[0x6], *(u16 *)(d + 0x7), d[0x9], d[0xA], name,
+			     DMI_DEV_TYPE_DEV_ONBOARD);
+	dmi_save_one_device(d[0x5] & 0x7f, name);
+}
+
+static void __init dmi_save_system_slot(const struct dmi_header *dm)
+{
+	const u8 *d = (u8 *)dm;
+
+	/* Need SMBIOS 2.6+ structure */
+	if (dm->length < 0x11)
+		return;
+	dmi_save_dev_pciaddr(*(u16 *)(d + 0x9), *(u16 *)(d + 0xD), d[0xF],
+			     d[0x10], dmi_string_nosave(dm, d[0x4]),
+			     DMI_DEV_TYPE_DEV_SLOT);
 }
 
 static void __init count_mem_devices(const struct dmi_header *dm, void *v)
@@ -426,6 +445,9 @@
 		dmi_save_ident(dm, DMI_CHASSIS_SERIAL, 7);
 		dmi_save_ident(dm, DMI_CHASSIS_ASSET_TAG, 8);
 		break;
+	case 9:		/* System Slots */
+		dmi_save_system_slot(dm);
+		break;
 	case 10:	/* Onboard Devices Information */
 		dmi_save_devices(dm);
 		break;
@@ -869,7 +891,7 @@
  *	@from: previous device found in search, or %NULL for new search.
  *
  *	Iterates through the list of known onboard devices. If a device is
- *	found with a matching @vendor and @device, a pointer to its device
+ *	found with a matching @type and @name, a pointer to its device
  *	structure is returned.  Otherwise, %NULL is returned.
  *	A new search is initiated by passing %NULL as the @from argument.
  *	If @from is not %NULL, searches continue from next device.
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index b18bea0..cb212eb 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -134,8 +134,8 @@
 
 config GPIO_BRCMSTB
 	tristate "BRCMSTB GPIO support"
-	default y if ARCH_BRCMSTB
-	depends on OF_GPIO && (ARCH_BRCMSTB || COMPILE_TEST)
+	default y if (ARCH_BRCMSTB || BMIPS_GENERIC)
+	depends on OF_GPIO && (ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST)
 	select GPIO_GENERIC
 	select GPIOLIB_IRQCHIP
 	help
@@ -496,8 +496,21 @@
 
 config GPIO_104_IDIO_16
 	tristate "ACCES 104-IDIO-16 GPIO support"
+	select GPIOLIB_IRQCHIP
 	help
-	  Enables GPIO support for the ACCES 104-IDIO-16 family.
+	  Enables GPIO support for the ACCES 104-IDIO-16 family. The base port
+	  address for the device may be set via the idio_16_base module
+	  parameter. The interrupt line number for the device may be set via the
+	  idio_16_irq module parameter.
+
+config GPIO_104_IDI_48
+	tristate "ACCES 104-IDI-48 GPIO support"
+	select GPIOLIB_IRQCHIP
+	help
+	  Enables GPIO support for the ACCES 104-IDI-48 family. The base port
+	  address for the device may be configured via the idi_48_base module
+	  parameter. The interrupt line number for the device may be configured
+	  via the idi_48_irq module parameter.
 
 config GPIO_F7188X
 	tristate "F71869, F71869A, F71882FG and F71889F GPIO support"
@@ -907,7 +920,6 @@
 
 config GPIO_AMD8111
 	tristate "AMD 8111 GPIO driver"
-	depends on PCI
 	help
 	  The AMD 8111 south bridge contains 32 GPIO pins which can be used.
 
@@ -919,7 +931,7 @@
 
 config GPIO_BT8XX
 	tristate "BT8XX GPIO abuser"
-	depends on PCI && VIDEO_BT848=n
+	depends on VIDEO_BT848=n
 	help
 	  The BT8xx frame grabber chip has 24 GPIO pins that can be abused
 	  as a cheap PCI GPIO card.
@@ -935,14 +947,13 @@
 
 config GPIO_INTEL_MID
 	bool "Intel Mid GPIO support"
-	depends on PCI && X86
+	depends on X86
 	select GPIOLIB_IRQCHIP
 	help
 	  Say Y here to support Intel Mid GPIO.
 
 config GPIO_ML_IOH
 	tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
-	depends on PCI
 	select GENERIC_IRQ_CHIP
 	help
 	  ML7213 is companion chip for Intel Atom E6xx series.
@@ -952,7 +963,7 @@
 
 config GPIO_PCH
 	tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7223/ML7831) GPIO"
-	depends on PCI && (X86_32 || COMPILE_TEST)
+	depends on X86_32 || MIPS || COMPILE_TEST
 	select GENERIC_IRQ_CHIP
 	help
 	  This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff
@@ -968,7 +979,6 @@
 
 config GPIO_RDC321X
 	tristate "RDC R-321x GPIO support"
-	depends on PCI
 	select MFD_CORE
 	select MFD_RDC321X
 	help
@@ -977,7 +987,7 @@
 
 config GPIO_SODAVILLE
 	bool "Intel Sodaville GPIO support"
-	depends on X86 && PCI && OF
+	depends on X86 && OF
 	select GPIO_GENERIC
 	select GENERIC_IRQ_CHIP
 	help
@@ -1028,7 +1038,7 @@
 
 config GPIO_VIPERBOARD
 	tristate "Viperboard GPIO a & b support"
-	depends on MFD_VIPERBOARD && USB
+	depends on MFD_VIPERBOARD
 	help
 	  Say yes here to access the GPIO signals of Nano River
 	  Technologies Viperboard. There are two GPIO chips on the
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 986dbd8..548e9b5 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -13,6 +13,7 @@
 obj-$(CONFIG_GPIO_GENERIC)	+= gpio-generic.o
 
 obj-$(CONFIG_GPIO_104_IDIO_16)	+= gpio-104-idio-16.o
+obj-$(CONFIG_GPIO_104_IDI_48)	+= gpio-104-idi-48.o
 obj-$(CONFIG_GPIO_74X164)	+= gpio-74x164.o
 obj-$(CONFIG_GPIO_74XX_MMIO)	+= gpio-74xx-mmio.o
 obj-$(CONFIG_GPIO_ADNP)		+= gpio-adnp.o
diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c
new file mode 100644
index 0000000..52eed32
--- /dev/null
+++ b/drivers/gpio/gpio-104-idi-48.c
@@ -0,0 +1,343 @@
+/*
+ * GPIO driver for the ACCES 104-IDI-48 family
+ * Copyright (C) 2015 William Breathitt Gray
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/irqdesc.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+static unsigned idi_48_base;
+module_param(idi_48_base, uint, 0);
+MODULE_PARM_DESC(idi_48_base, "ACCES 104-IDI-48 base address");
+static unsigned idi_48_irq;
+module_param(idi_48_irq, uint, 0);
+MODULE_PARM_DESC(idi_48_irq, "ACCES 104-IDI-48 interrupt line number");
+
+/**
+ * struct idi_48_gpio - GPIO device private data structure
+ * @chip:	instance of the gpio_chip
+ * @lock:	synchronization lock to prevent I/O race conditions
+ * @ack_lock:	synchronization lock to prevent IRQ handler race conditions
+ * @irq_mask:	input bits affected by interrupts
+ * @base:	base port address of the GPIO device
+ * @extent:	extent of port address region of the GPIO device
+ * @irq:	Interrupt line number
+ * @cos_enb:	Change-Of-State IRQ enable boundaries mask
+ */
+struct idi_48_gpio {
+	struct gpio_chip chip;
+	spinlock_t lock;
+	spinlock_t ack_lock;
+	unsigned char irq_mask[6];
+	unsigned base;
+	unsigned extent;
+	unsigned irq;
+	unsigned char cos_enb;
+};
+
+static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+	return 1;
+}
+
+static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	return 0;
+}
+
+static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
+	unsigned i;
+	const unsigned register_offset[6] = { 0, 1, 2, 4, 5, 6 };
+	unsigned base_offset;
+	unsigned mask;
+
+	for (i = 0; i < 48; i += 8)
+		if (offset < i + 8) {
+			base_offset = register_offset[i / 8];
+			mask = BIT(offset - i);
+
+			return !!(inb(idi48gpio->base + base_offset) & mask);
+		}
+
+	/* The following line should never execute since offset < 48 */
+	return 0;
+}
+
+static void idi_48_irq_ack(struct irq_data *data)
+{
+}
+
+static void idi_48_irq_mask(struct irq_data *data)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+	struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
+	const unsigned offset = irqd_to_hwirq(data);
+	unsigned i;
+	unsigned mask;
+	unsigned boundary;
+	unsigned long flags;
+
+	for (i = 0; i < 48; i += 8)
+		if (offset < i + 8) {
+			mask = BIT(offset - i);
+			boundary = i / 8;
+
+			idi48gpio->irq_mask[boundary] &= ~mask;
+
+			if (!idi48gpio->irq_mask[boundary]) {
+				idi48gpio->cos_enb &= ~BIT(boundary);
+
+				spin_lock_irqsave(&idi48gpio->lock, flags);
+
+				outb(idi48gpio->cos_enb, idi48gpio->base + 7);
+
+				spin_unlock_irqrestore(&idi48gpio->lock, flags);
+			}
+
+			return;
+		}
+}
+
+static void idi_48_irq_unmask(struct irq_data *data)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+	struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
+	const unsigned offset = irqd_to_hwirq(data);
+	unsigned i;
+	unsigned mask;
+	unsigned boundary;
+	unsigned prev_irq_mask;
+	unsigned long flags;
+
+	for (i = 0; i < 48; i += 8)
+		if (offset < i + 8) {
+			mask = BIT(offset - i);
+			boundary = i / 8;
+			prev_irq_mask = idi48gpio->irq_mask[boundary];
+
+			idi48gpio->irq_mask[boundary] |= mask;
+
+			if (!prev_irq_mask) {
+				idi48gpio->cos_enb |= BIT(boundary);
+
+				spin_lock_irqsave(&idi48gpio->lock, flags);
+
+				outb(idi48gpio->cos_enb, idi48gpio->base + 7);
+
+				spin_unlock_irqrestore(&idi48gpio->lock, flags);
+			}
+
+			return;
+		}
+}
+
+static int idi_48_irq_set_type(struct irq_data *data, unsigned flow_type)
+{
+	/* The only valid irq types are none and both-edges */
+	if (flow_type != IRQ_TYPE_NONE &&
+		(flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
+		return -EINVAL;
+
+	return 0;
+}
+
+static struct irq_chip idi_48_irqchip = {
+	.name = "104-idi-48",
+	.irq_ack = idi_48_irq_ack,
+	.irq_mask = idi_48_irq_mask,
+	.irq_unmask = idi_48_irq_unmask,
+	.irq_set_type = idi_48_irq_set_type
+};
+
+static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
+{
+	struct idi_48_gpio *const idi48gpio = dev_id;
+	unsigned long cos_status;
+	unsigned long boundary;
+	unsigned long irq_mask;
+	unsigned long bit_num;
+	unsigned long gpio;
+	struct gpio_chip *const chip = &idi48gpio->chip;
+
+	spin_lock(&idi48gpio->ack_lock);
+
+	spin_lock(&idi48gpio->lock);
+
+	cos_status = inb(idi48gpio->base + 7);
+
+	spin_unlock(&idi48gpio->lock);
+
+	/* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */
+	if (cos_status & BIT(6)) {
+		spin_unlock(&idi48gpio->ack_lock);
+		return IRQ_NONE;
+	}
+
+	/* Bit 0-5 indicate which Change-Of-State boundary triggered the IRQ */
+	cos_status &= 0x3F;
+
+	for_each_set_bit(boundary, &cos_status, 6) {
+		irq_mask = idi48gpio->irq_mask[boundary];
+
+		for_each_set_bit(bit_num, &irq_mask, 8) {
+			gpio = bit_num + boundary * 8;
+
+			generic_handle_irq(irq_find_mapping(chip->irqdomain,
+				gpio));
+		}
+	}
+
+	spin_unlock(&idi48gpio->ack_lock);
+
+	return IRQ_HANDLED;
+}
+
+static int __init idi_48_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct idi_48_gpio *idi48gpio;
+	const unsigned base = idi_48_base;
+	const unsigned extent = 8;
+	const char *const name = dev_name(dev);
+	int err;
+	const unsigned irq = idi_48_irq;
+
+	idi48gpio = devm_kzalloc(dev, sizeof(*idi48gpio), GFP_KERNEL);
+	if (!idi48gpio)
+		return -ENOMEM;
+
+	if (!request_region(base, extent, name)) {
+		dev_err(dev, "Unable to lock %s port addresses (0x%X-0x%X)\n",
+			name, base, base + extent);
+		err = -EBUSY;
+		goto err_lock_io_port;
+	}
+
+	idi48gpio->chip.label = name;
+	idi48gpio->chip.parent = dev;
+	idi48gpio->chip.owner = THIS_MODULE;
+	idi48gpio->chip.base = -1;
+	idi48gpio->chip.ngpio = 48;
+	idi48gpio->chip.get_direction = idi_48_gpio_get_direction;
+	idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
+	idi48gpio->chip.get = idi_48_gpio_get;
+	idi48gpio->base = base;
+	idi48gpio->extent = extent;
+	idi48gpio->irq = irq;
+
+	spin_lock_init(&idi48gpio->lock);
+
+	dev_set_drvdata(dev, idi48gpio);
+
+	err = gpiochip_add_data(&idi48gpio->chip, idi48gpio);
+	if (err) {
+		dev_err(dev, "GPIO registering failed (%d)\n", err);
+		goto err_gpio_register;
+	}
+
+	/* Disable IRQ by default */
+	outb(0, base + 7);
+	inb(base + 7);
+
+	err = gpiochip_irqchip_add(&idi48gpio->chip, &idi_48_irqchip, 0,
+		handle_edge_irq, IRQ_TYPE_NONE);
+	if (err) {
+		dev_err(dev, "Could not add irqchip (%d)\n", err);
+		goto err_gpiochip_irqchip_add;
+	}
+
+	err = request_irq(irq, idi_48_irq_handler, 0, name, idi48gpio);
+	if (err) {
+		dev_err(dev, "IRQ handler registering failed (%d)\n", err);
+		goto err_request_irq;
+	}
+
+	return 0;
+
+err_request_irq:
+err_gpiochip_irqchip_add:
+	gpiochip_remove(&idi48gpio->chip);
+err_gpio_register:
+	release_region(base, extent);
+err_lock_io_port:
+	return err;
+}
+
+static int idi_48_remove(struct platform_device *pdev)
+{
+	struct idi_48_gpio *const idi48gpio = platform_get_drvdata(pdev);
+
+	free_irq(idi48gpio->irq, idi48gpio);
+	gpiochip_remove(&idi48gpio->chip);
+	release_region(idi48gpio->base, idi48gpio->extent);
+
+	return 0;
+}
+
+static struct platform_device *idi_48_device;
+
+static struct platform_driver idi_48_driver = {
+	.driver = {
+		.name = "104-idi-48"
+	},
+	.remove = idi_48_remove
+};
+
+static void __exit idi_48_exit(void)
+{
+	platform_device_unregister(idi_48_device);
+	platform_driver_unregister(&idi_48_driver);
+}
+
+static int __init idi_48_init(void)
+{
+	int err;
+
+	idi_48_device = platform_device_alloc(idi_48_driver.driver.name, -1);
+	if (!idi_48_device)
+		return -ENOMEM;
+
+	err = platform_device_add(idi_48_device);
+	if (err)
+		goto err_platform_device;
+
+	err = platform_driver_probe(&idi_48_driver, idi_48_probe);
+	if (err)
+		goto err_platform_driver;
+
+	return 0;
+
+err_platform_driver:
+	platform_device_del(idi_48_device);
+err_platform_device:
+	platform_device_put(idi_48_device);
+	return err;
+}
+
+module_init(idi_48_init);
+module_exit(idi_48_exit);
+
+MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
+MODULE_DESCRIPTION("ACCES 104-IDI-48 GPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c
index 5400d7d..4d69b50 100644
--- a/drivers/gpio/gpio-104-idio-16.c
+++ b/drivers/gpio/gpio-104-idio-16.c
@@ -11,11 +11,14 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  */
+#include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/errno.h>
 #include <linux/gpio/driver.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/irqdesc.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -25,20 +28,27 @@
 static unsigned idio_16_base;
 module_param(idio_16_base, uint, 0);
 MODULE_PARM_DESC(idio_16_base, "ACCES 104-IDIO-16 base address");
+static unsigned idio_16_irq;
+module_param(idio_16_irq, uint, 0);
+MODULE_PARM_DESC(idio_16_irq, "ACCES 104-IDIO-16 interrupt line number");
 
 /**
  * struct idio_16_gpio - GPIO device private data structure
  * @chip:	instance of the gpio_chip
- * @lock:	synchronization lock to prevent gpio_set race conditions
+ * @lock:	synchronization lock to prevent I/O race conditions
+ * @irq_mask:	I/O bits affected by interrupts
  * @base:	base port address of the GPIO device
  * @extent:	extent of port address region of the GPIO device
+ * @irq:	Interrupt line number
  * @out_state:	output bits state
  */
 struct idio_16_gpio {
 	struct gpio_chip chip;
 	spinlock_t lock;
+	unsigned long irq_mask;
 	unsigned base;
 	unsigned extent;
+	unsigned irq;
 	unsigned out_state;
 };
 
@@ -62,29 +72,24 @@
 	return 0;
 }
 
-static struct idio_16_gpio *to_idio16gpio(struct gpio_chip *gc)
-{
-	return container_of(gc, struct idio_16_gpio, chip);
-}
-
 static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct idio_16_gpio *const idio16gpio = to_idio16gpio(chip);
-	const unsigned BIT_MASK = 1U << (offset-16);
+	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+	const unsigned mask = BIT(offset-16);
 
 	if (offset < 16)
 		return -EINVAL;
 
 	if (offset < 24)
-		return !!(inb(idio16gpio->base + 1) & BIT_MASK);
+		return !!(inb(idio16gpio->base + 1) & mask);
 
-	return !!(inb(idio16gpio->base + 5) & (BIT_MASK>>8));
+	return !!(inb(idio16gpio->base + 5) & (mask>>8));
 }
 
 static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct idio_16_gpio *const idio16gpio = to_idio16gpio(chip);
-	const unsigned BIT_MASK = 1U << offset;
+	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+	const unsigned mask = BIT(offset);
 	unsigned long flags;
 
 	if (offset > 15)
@@ -93,9 +98,9 @@
 	spin_lock_irqsave(&idio16gpio->lock, flags);
 
 	if (value)
-		idio16gpio->out_state |= BIT_MASK;
+		idio16gpio->out_state |= mask;
 	else
-		idio16gpio->out_state &= ~BIT_MASK;
+		idio16gpio->out_state &= ~mask;
 
 	if (offset > 7)
 		outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
@@ -105,29 +110,106 @@
 	spin_unlock_irqrestore(&idio16gpio->lock, flags);
 }
 
+static void idio_16_irq_ack(struct irq_data *data)
+{
+}
+
+static void idio_16_irq_mask(struct irq_data *data)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+	const unsigned long mask = BIT(irqd_to_hwirq(data));
+	unsigned long flags;
+
+	idio16gpio->irq_mask &= ~mask;
+
+	if (!idio16gpio->irq_mask) {
+		spin_lock_irqsave(&idio16gpio->lock, flags);
+
+		outb(0, idio16gpio->base + 2);
+
+		spin_unlock_irqrestore(&idio16gpio->lock, flags);
+	}
+}
+
+static void idio_16_irq_unmask(struct irq_data *data)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+	const unsigned long mask = BIT(irqd_to_hwirq(data));
+	const unsigned long prev_irq_mask = idio16gpio->irq_mask;
+	unsigned long flags;
+
+	idio16gpio->irq_mask |= mask;
+
+	if (!prev_irq_mask) {
+		spin_lock_irqsave(&idio16gpio->lock, flags);
+
+		inb(idio16gpio->base + 2);
+
+		spin_unlock_irqrestore(&idio16gpio->lock, flags);
+	}
+}
+
+static int idio_16_irq_set_type(struct irq_data *data, unsigned flow_type)
+{
+	/* The only valid irq types are none and both-edges */
+	if (flow_type != IRQ_TYPE_NONE &&
+		(flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
+		return -EINVAL;
+
+	return 0;
+}
+
+static struct irq_chip idio_16_irqchip = {
+	.name = "104-idio-16",
+	.irq_ack = idio_16_irq_ack,
+	.irq_mask = idio_16_irq_mask,
+	.irq_unmask = idio_16_irq_unmask,
+	.irq_set_type = idio_16_irq_set_type
+};
+
+static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
+{
+	struct idio_16_gpio *const idio16gpio = dev_id;
+	struct gpio_chip *const chip = &idio16gpio->chip;
+	int gpio;
+
+	for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
+		generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio));
+
+	spin_lock(&idio16gpio->lock);
+
+	outb(0, idio16gpio->base + 1);
+
+	spin_unlock(&idio16gpio->lock);
+
+	return IRQ_HANDLED;
+}
+
 static int __init idio_16_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct idio_16_gpio *idio16gpio;
+	const unsigned base = idio_16_base;
+	const unsigned extent = 8;
+	const char *const name = dev_name(dev);
 	int err;
-
-	const unsigned BASE = idio_16_base;
-	const unsigned EXTENT = 8;
-	const char *const NAME = dev_name(dev);
+	const unsigned irq = idio_16_irq;
 
 	idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
 	if (!idio16gpio)
 		return -ENOMEM;
 
-	if (!request_region(BASE, EXTENT, NAME)) {
+	if (!request_region(base, extent, name)) {
 		dev_err(dev, "Unable to lock %s port addresses (0x%X-0x%X)\n",
-			NAME, BASE, BASE + EXTENT);
+			name, base, base + extent);
 		err = -EBUSY;
 		goto err_lock_io_port;
 	}
 
-	idio16gpio->chip.label = NAME;
-	idio16gpio->chip.dev = dev;
+	idio16gpio->chip.label = name;
+	idio16gpio->chip.parent = dev;
 	idio16gpio->chip.owner = THIS_MODULE;
 	idio16gpio->chip.base = -1;
 	idio16gpio->chip.ngpio = 32;
@@ -136,24 +218,45 @@
 	idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
 	idio16gpio->chip.get = idio_16_gpio_get;
 	idio16gpio->chip.set = idio_16_gpio_set;
-	idio16gpio->base = BASE;
-	idio16gpio->extent = EXTENT;
+	idio16gpio->base = base;
+	idio16gpio->extent = extent;
+	idio16gpio->irq = irq;
 	idio16gpio->out_state = 0xFFFF;
 
 	spin_lock_init(&idio16gpio->lock);
 
 	dev_set_drvdata(dev, idio16gpio);
 
-	err = gpiochip_add(&idio16gpio->chip);
+	err = gpiochip_add_data(&idio16gpio->chip, idio16gpio);
 	if (err) {
 		dev_err(dev, "GPIO registering failed (%d)\n", err);
 		goto err_gpio_register;
 	}
 
+	/* Disable IRQ by default */
+	outb(0, base + 2);
+	outb(0, base + 1);
+
+	err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0,
+		handle_edge_irq, IRQ_TYPE_NONE);
+	if (err) {
+		dev_err(dev, "Could not add irqchip (%d)\n", err);
+		goto err_gpiochip_irqchip_add;
+	}
+
+	err = request_irq(irq, idio_16_irq_handler, 0, name, idio16gpio);
+	if (err) {
+		dev_err(dev, "IRQ handler registering failed (%d)\n", err);
+		goto err_request_irq;
+	}
+
 	return 0;
 
+err_request_irq:
+err_gpiochip_irqchip_add:
+	gpiochip_remove(&idio16gpio->chip);
 err_gpio_register:
-	release_region(BASE, EXTENT);
+	release_region(base, extent);
 err_lock_io_port:
 	return err;
 }
@@ -162,6 +265,7 @@
 {
 	struct idio_16_gpio *const idio16gpio = platform_get_drvdata(pdev);
 
+	free_irq(idio16gpio->irq, idio16gpio);
 	gpiochip_remove(&idio16gpio->chip);
 	release_region(idio16gpio->base, idio16gpio->extent);
 
diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c
index 60172f8..c81224f 100644
--- a/drivers/gpio/gpio-74x164.c
+++ b/drivers/gpio/gpio-74x164.c
@@ -20,56 +20,34 @@
 #define GEN_74X164_NUMBER_GPIOS	8
 
 struct gen_74x164_chip {
-	u8			*buffer;
 	struct gpio_chip	gpio_chip;
 	struct mutex		lock;
 	u32			registers;
-};
-
-static struct gen_74x164_chip *gpio_to_74x164_chip(struct gpio_chip *gc)
-{
-	return container_of(gc, struct gen_74x164_chip, gpio_chip);
-}
-
-static int __gen_74x164_write_config(struct gen_74x164_chip *chip)
-{
-	struct spi_device *spi = to_spi_device(chip->gpio_chip.dev);
-	struct spi_message message;
-	struct spi_transfer *msg_buf;
-	int i, ret = 0;
-
-	msg_buf = kzalloc(chip->registers * sizeof(struct spi_transfer),
-			GFP_KERNEL);
-	if (!msg_buf)
-		return -ENOMEM;
-
-	spi_message_init(&message);
-
 	/*
 	 * Since the registers are chained, every byte sent will make
 	 * the previous byte shift to the next register in the
-	 * chain. Thus, the first byte send will end up in the last
+	 * chain. Thus, the first byte sent will end up in the last
 	 * register at the end of the transfer. So, to have a logical
-	 * numbering, send the bytes in reverse order so that the last
-	 * byte of the buffer will end up in the last register.
+	 * numbering, store the bytes in reverse order.
 	 */
-	for (i = chip->registers - 1; i >= 0; i--) {
-		msg_buf[i].tx_buf = chip->buffer + i;
-		msg_buf[i].len = sizeof(u8);
-		spi_message_add_tail(msg_buf + i, &message);
-	}
+	u8			buffer[0];
+};
 
-	ret = spi_sync(spi, &message);
+static int __gen_74x164_write_config(struct gen_74x164_chip *chip)
+{
+	struct spi_transfer xfer = {
+		.tx_buf = chip->buffer,
+		.len = chip->registers,
+	};
 
-	kfree(msg_buf);
-
-	return ret;
+	return spi_sync_transfer(to_spi_device(chip->gpio_chip.parent),
+				 &xfer, 1);
 }
 
 static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset)
 {
-	struct gen_74x164_chip *chip = gpio_to_74x164_chip(gc);
-	u8 bank = offset / 8;
+	struct gen_74x164_chip *chip = gpiochip_get_data(gc);
+	u8 bank = chip->registers - 1 - offset / 8;
 	u8 pin = offset % 8;
 	int ret;
 
@@ -83,8 +61,8 @@
 static void gen_74x164_set_value(struct gpio_chip *gc,
 		unsigned offset, int val)
 {
-	struct gen_74x164_chip *chip = gpio_to_74x164_chip(gc);
-	u8 bank = offset / 8;
+	struct gen_74x164_chip *chip = gpiochip_get_data(gc);
+	u8 bank = chip->registers - 1 - offset / 8;
 	u8 pin = offset % 8;
 
 	mutex_lock(&chip->lock);
@@ -107,6 +85,7 @@
 static int gen_74x164_probe(struct spi_device *spi)
 {
 	struct gen_74x164_chip *chip;
+	u32 nregs;
 	int ret;
 
 	/*
@@ -118,7 +97,14 @@
 	if (ret < 0)
 		return ret;
 
-	chip = devm_kzalloc(&spi->dev, sizeof(*chip), GFP_KERNEL);
+	if (of_property_read_u32(spi->dev.of_node, "registers-number",
+				 &nregs)) {
+		dev_err(&spi->dev,
+			"Missing registers-number property in the DT.\n");
+		return -EINVAL;
+	}
+
+	chip = devm_kzalloc(&spi->dev, sizeof(*chip) + nregs, GFP_KERNEL);
 	if (!chip)
 		return -ENOMEM;
 
@@ -130,20 +116,11 @@
 	chip->gpio_chip.set = gen_74x164_set_value;
 	chip->gpio_chip.base = -1;
 
-	if (of_property_read_u32(spi->dev.of_node, "registers-number",
-				 &chip->registers)) {
-		dev_err(&spi->dev,
-			"Missing registers-number property in the DT.\n");
-		return -EINVAL;
-	}
-
+	chip->registers = nregs;
 	chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers;
-	chip->buffer = devm_kzalloc(&spi->dev, chip->registers, GFP_KERNEL);
-	if (!chip->buffer)
-		return -ENOMEM;
 
 	chip->gpio_chip.can_sleep = true;
-	chip->gpio_chip.dev = &spi->dev;
+	chip->gpio_chip.parent = &spi->dev;
 	chip->gpio_chip.owner = THIS_MODULE;
 
 	mutex_init(&chip->lock);
@@ -154,7 +131,7 @@
 		goto exit_destroy;
 	}
 
-	ret = gpiochip_add(&chip->gpio_chip);
+	ret = gpiochip_add_data(&chip->gpio_chip, chip);
 	if (!ret)
 		return 0;
 
diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c
index 6b18682..372b0e0 100644
--- a/drivers/gpio/gpio-74xx-mmio.c
+++ b/drivers/gpio/gpio-74xx-mmio.c
@@ -10,10 +10,9 @@
  */
 
 #include <linux/err.h>
-#include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/platform_device.h>
 
 #define MMIO_74XX_DIR_IN	(0 << 8)
@@ -21,7 +20,7 @@
 #define MMIO_74XX_BIT_CNT(x)	((x) & 0xff)
 
 struct mmio_74xx_gpio_priv {
-	struct bgpio_chip	bgc;
+	struct gpio_chip	gc;
 	unsigned		flags;
 };
 
@@ -78,30 +77,23 @@
 };
 MODULE_DEVICE_TABLE(of, mmio_74xx_gpio_ids);
 
-static inline struct mmio_74xx_gpio_priv *to_74xx_gpio(struct gpio_chip *gc)
-{
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
-	return container_of(bgc, struct mmio_74xx_gpio_priv, bgc);
-}
-
 static int mmio_74xx_get_direction(struct gpio_chip *gc, unsigned offset)
 {
-	struct mmio_74xx_gpio_priv *priv = to_74xx_gpio(gc);
+	struct mmio_74xx_gpio_priv *priv = gpiochip_get_data(gc);
 
-	return (priv->flags & MMIO_74XX_DIR_OUT) ? GPIOF_DIR_OUT : GPIOF_DIR_IN;
+	return !(priv->flags & MMIO_74XX_DIR_OUT);
 }
 
 static int mmio_74xx_dir_in(struct gpio_chip *gc, unsigned int gpio)
 {
-	struct mmio_74xx_gpio_priv *priv = to_74xx_gpio(gc);
+	struct mmio_74xx_gpio_priv *priv = gpiochip_get_data(gc);
 
 	return (priv->flags & MMIO_74XX_DIR_OUT) ? -ENOTSUPP : 0;
 }
 
 static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 {
-	struct mmio_74xx_gpio_priv *priv = to_74xx_gpio(gc);
+	struct mmio_74xx_gpio_priv *priv = gpiochip_get_data(gc);
 
 	if (priv->flags & MMIO_74XX_DIR_OUT) {
 		gc->set(gc, gpio, val);
@@ -134,28 +126,29 @@
 
 	priv->flags = (uintptr_t) of_id->data;
 
-	err = bgpio_init(&priv->bgc, &pdev->dev,
+	err = bgpio_init(&priv->gc, &pdev->dev,
 			 DIV_ROUND_UP(MMIO_74XX_BIT_CNT(priv->flags), 8),
 			 dat, NULL, NULL, NULL, NULL, 0);
 	if (err)
 		return err;
 
-	priv->bgc.gc.direction_input = mmio_74xx_dir_in;
-	priv->bgc.gc.direction_output = mmio_74xx_dir_out;
-	priv->bgc.gc.get_direction = mmio_74xx_get_direction;
-	priv->bgc.gc.ngpio = MMIO_74XX_BIT_CNT(priv->flags);
-	priv->bgc.gc.owner = THIS_MODULE;
+	priv->gc.direction_input = mmio_74xx_dir_in;
+	priv->gc.direction_output = mmio_74xx_dir_out;
+	priv->gc.get_direction = mmio_74xx_get_direction;
+	priv->gc.ngpio = MMIO_74XX_BIT_CNT(priv->flags);
+	priv->gc.owner = THIS_MODULE;
 
 	platform_set_drvdata(pdev, priv);
 
-	return gpiochip_add(&priv->bgc.gc);
+	return gpiochip_add_data(&priv->gc, priv);
 }
 
 static int mmio_74xx_gpio_remove(struct platform_device *pdev)
 {
 	struct mmio_74xx_gpio_priv *priv = platform_get_drvdata(pdev);
 
-	return bgpio_remove(&priv->bgc);
+	gpiochip_remove(&priv->gc);
+	return 0;
 }
 
 static struct platform_driver mmio_74xx_gpio_driver = {
diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c
index d3d0a90..fb5b47b 100644
--- a/drivers/gpio/gpio-adnp.c
+++ b/drivers/gpio/gpio-adnp.c
@@ -36,18 +36,13 @@
 	u8 *irq_low;
 };
 
-static inline struct adnp *to_adnp(struct gpio_chip *chip)
-{
-	return container_of(chip, struct adnp, gpio);
-}
-
 static int adnp_read(struct adnp *adnp, unsigned offset, uint8_t *value)
 {
 	int err;
 
 	err = i2c_smbus_read_byte_data(adnp->client, offset);
 	if (err < 0) {
-		dev_err(adnp->gpio.dev, "%s failed: %d\n",
+		dev_err(adnp->gpio.parent, "%s failed: %d\n",
 			"i2c_smbus_read_byte_data()", err);
 		return err;
 	}
@@ -62,7 +57,7 @@
 
 	err = i2c_smbus_write_byte_data(adnp->client, offset, value);
 	if (err < 0) {
-		dev_err(adnp->gpio.dev, "%s failed: %d\n",
+		dev_err(adnp->gpio.parent, "%s failed: %d\n",
 			"i2c_smbus_write_byte_data()", err);
 		return err;
 	}
@@ -72,7 +67,7 @@
 
 static int adnp_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct adnp *adnp = to_adnp(chip);
+	struct adnp *adnp = gpiochip_get_data(chip);
 	unsigned int reg = offset >> adnp->reg_shift;
 	unsigned int pos = offset & 7;
 	u8 value;
@@ -106,7 +101,7 @@
 
 static void adnp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct adnp *adnp = to_adnp(chip);
+	struct adnp *adnp = gpiochip_get_data(chip);
 
 	mutex_lock(&adnp->i2c_lock);
 	__adnp_gpio_set(adnp, offset, value);
@@ -115,7 +110,7 @@
 
 static int adnp_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct adnp *adnp = to_adnp(chip);
+	struct adnp *adnp = gpiochip_get_data(chip);
 	unsigned int reg = offset >> adnp->reg_shift;
 	unsigned int pos = offset & 7;
 	u8 value;
@@ -150,7 +145,7 @@
 static int adnp_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 				      int value)
 {
-	struct adnp *adnp = to_adnp(chip);
+	struct adnp *adnp = gpiochip_get_data(chip);
 	unsigned int reg = offset >> adnp->reg_shift;
 	unsigned int pos = offset & 7;
 	int err;
@@ -187,7 +182,7 @@
 
 static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
-	struct adnp *adnp = to_adnp(chip);
+	struct adnp *adnp = gpiochip_get_data(chip);
 	unsigned int num_regs = 1 << adnp->reg_shift, i, j;
 	int err;
 
@@ -266,11 +261,11 @@
 	chip->base = -1;
 	chip->ngpio = num_gpios;
 	chip->label = adnp->client->name;
-	chip->dev = &adnp->client->dev;
-	chip->of_node = chip->dev->of_node;
+	chip->parent = &adnp->client->dev;
+	chip->of_node = chip->parent->of_node;
 	chip->owner = THIS_MODULE;
 
-	err = gpiochip_add(chip);
+	err = gpiochip_add_data(chip, adnp);
 	if (err)
 		return err;
 
@@ -340,7 +335,7 @@
 static void adnp_irq_mask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct adnp *adnp = to_adnp(gc);
+	struct adnp *adnp = gpiochip_get_data(gc);
 	unsigned int reg = d->hwirq >> adnp->reg_shift;
 	unsigned int pos = d->hwirq & 7;
 
@@ -350,7 +345,7 @@
 static void adnp_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct adnp *adnp = to_adnp(gc);
+	struct adnp *adnp = gpiochip_get_data(gc);
 	unsigned int reg = d->hwirq >> adnp->reg_shift;
 	unsigned int pos = d->hwirq & 7;
 
@@ -360,7 +355,7 @@
 static int adnp_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct adnp *adnp = to_adnp(gc);
+	struct adnp *adnp = gpiochip_get_data(gc);
 	unsigned int reg = d->hwirq >> adnp->reg_shift;
 	unsigned int pos = d->hwirq & 7;
 
@@ -390,7 +385,7 @@
 static void adnp_irq_bus_lock(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct adnp *adnp = to_adnp(gc);
+	struct adnp *adnp = gpiochip_get_data(gc);
 
 	mutex_lock(&adnp->irq_lock);
 }
@@ -398,7 +393,7 @@
 static void adnp_irq_bus_unlock(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct adnp *adnp = to_adnp(gc);
+	struct adnp *adnp = gpiochip_get_data(gc);
 	unsigned int num_regs = 1 << adnp->reg_shift, i;
 
 	mutex_lock(&adnp->i2c_lock);
@@ -435,7 +430,8 @@
 	 * is chosen to match the register layout of the hardware in that
 	 * each segment contains the corresponding bits for all interrupts.
 	 */
-	adnp->irq_enable = devm_kzalloc(chip->dev, num_regs * 6, GFP_KERNEL);
+	adnp->irq_enable = devm_kzalloc(chip->parent, num_regs * 6,
+					GFP_KERNEL);
 	if (!adnp->irq_enable)
 		return -ENOMEM;
 
@@ -462,12 +458,12 @@
 		adnp->irq_enable[i] = 0x00;
 	}
 
-	err = devm_request_threaded_irq(chip->dev, adnp->client->irq,
+	err = devm_request_threaded_irq(chip->parent, adnp->client->irq,
 					NULL, adnp_irq,
 					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-					dev_name(chip->dev), adnp);
+					dev_name(chip->parent), adnp);
 	if (err != 0) {
-		dev_err(chip->dev, "can't request IRQ#%d: %d\n",
+		dev_err(chip->parent, "can't request IRQ#%d: %d\n",
 			adnp->client->irq, err);
 		return err;
 	}
@@ -478,7 +474,7 @@
 				   handle_simple_irq,
 				   IRQ_TYPE_NONE);
 	if (err) {
-		dev_err(chip->dev,
+		dev_err(chip->parent,
 			"could not connect irqchip to gpiochip\n");
 		return err;
 	}
@@ -547,7 +543,6 @@
 static struct i2c_driver adnp_i2c_driver = {
 	.driver = {
 		.name = "gpio-adnp",
-		.owner = THIS_MODULE,
 		.of_match_table = adnp_of_match,
 	},
 	.probe = adnp_i2c_probe,
diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c
index caff711..4fa7ff1 100644
--- a/drivers/gpio/gpio-adp5520.c
+++ b/drivers/gpio/gpio-adp5520.c
@@ -27,7 +27,7 @@
 	struct adp5520_gpio *dev;
 	uint8_t reg_val;
 
-	dev = container_of(chip, struct adp5520_gpio, gpio_chip);
+	dev = gpiochip_get_data(chip);
 
 	/*
 	 * There are dedicated registers for GPIO IN/OUT.
@@ -46,7 +46,7 @@
 		unsigned off, int val)
 {
 	struct adp5520_gpio *dev;
-	dev = container_of(chip, struct adp5520_gpio, gpio_chip);
+	dev = gpiochip_get_data(chip);
 
 	if (val)
 		adp5520_set_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
@@ -57,7 +57,7 @@
 static int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off)
 {
 	struct adp5520_gpio *dev;
-	dev = container_of(chip, struct adp5520_gpio, gpio_chip);
+	dev = gpiochip_get_data(chip);
 
 	clear_bit(off, &dev->output);
 
@@ -70,7 +70,7 @@
 {
 	struct adp5520_gpio *dev;
 	int ret = 0;
-	dev = container_of(chip, struct adp5520_gpio, gpio_chip);
+	dev = gpiochip_get_data(chip);
 
 	set_bit(off, &dev->output);
 
@@ -153,7 +153,7 @@
 		goto err;
 	}
 
-	ret = gpiochip_add(&dev->gpio_chip);
+	ret = gpiochip_add_data(&dev->gpio_chip, dev);
 	if (ret)
 		goto err;
 
diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c
index 984186e..19a0eba 100644
--- a/drivers/gpio/gpio-adp5588.c
+++ b/drivers/gpio/gpio-adp5588.c
@@ -65,8 +65,7 @@
 
 static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
 {
-	struct adp5588_gpio *dev =
-	    container_of(chip, struct adp5588_gpio, gpio_chip);
+	struct adp5588_gpio *dev = gpiochip_get_data(chip);
 	unsigned bank = ADP5588_BANK(off);
 	unsigned bit = ADP5588_BIT(off);
 	int val;
@@ -87,8 +86,7 @@
 				   unsigned off, int val)
 {
 	unsigned bank, bit;
-	struct adp5588_gpio *dev =
-	    container_of(chip, struct adp5588_gpio, gpio_chip);
+	struct adp5588_gpio *dev = gpiochip_get_data(chip);
 
 	bank = ADP5588_BANK(off);
 	bit = ADP5588_BIT(off);
@@ -108,8 +106,7 @@
 {
 	int ret;
 	unsigned bank;
-	struct adp5588_gpio *dev =
-	    container_of(chip, struct adp5588_gpio, gpio_chip);
+	struct adp5588_gpio *dev = gpiochip_get_data(chip);
 
 	bank = ADP5588_BANK(off);
 
@@ -126,8 +123,7 @@
 {
 	int ret;
 	unsigned bank, bit;
-	struct adp5588_gpio *dev =
-	    container_of(chip, struct adp5588_gpio, gpio_chip);
+	struct adp5588_gpio *dev = gpiochip_get_data(chip);
 
 	bank = ADP5588_BANK(off);
 	bit = ADP5588_BIT(off);
@@ -152,8 +148,8 @@
 #ifdef CONFIG_GPIO_ADP5588_IRQ
 static int adp5588_gpio_to_irq(struct gpio_chip *chip, unsigned off)
 {
-	struct adp5588_gpio *dev =
-		container_of(chip, struct adp5588_gpio, gpio_chip);
+	struct adp5588_gpio *dev = gpiochip_get_data(chip);
+
 	return dev->irq_base + off;
 }
 
@@ -418,7 +414,7 @@
 		}
 	}
 
-	ret = gpiochip_add(&dev->gpio_chip);
+	ret = gpiochip_add_data(&dev->gpio_chip, dev);
 	if (ret)
 		goto err_irq;
 
diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c
index 3e6661b..2aeaebd 100644
--- a/drivers/gpio/gpio-altera.c
+++ b/drivers/gpio/gpio-altera.c
@@ -42,11 +42,6 @@
 	int mapped_irq;
 };
 
-static struct altera_gpio_chip *to_altera(struct gpio_chip *gc)
-{
-	return container_of(gc, struct altera_gpio_chip, mmchip.gc);
-}
-
 static void altera_gpio_irq_unmask(struct irq_data *d)
 {
 	struct altera_gpio_chip *altera_gc;
@@ -54,7 +49,7 @@
 	unsigned long flags;
 	u32 intmask;
 
-	altera_gc = to_altera(irq_data_get_irq_chip_data(d));
+	altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	mm_gc = &altera_gc->mmchip;
 
 	spin_lock_irqsave(&altera_gc->gpio_lock, flags);
@@ -72,7 +67,7 @@
 	unsigned long flags;
 	u32 intmask;
 
-	altera_gc = to_altera(irq_data_get_irq_chip_data(d));
+	altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	mm_gc = &altera_gc->mmchip;
 
 	spin_lock_irqsave(&altera_gc->gpio_lock, flags);
@@ -92,7 +87,7 @@
 {
 	struct altera_gpio_chip *altera_gc;
 
-	altera_gc = to_altera(irq_data_get_irq_chip_data(d));
+	altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d));
 
 	if (type == IRQ_TYPE_NONE)
 		return 0;
@@ -145,7 +140,7 @@
 	unsigned int data_reg;
 
 	mm_gc = to_of_mm_gpio_chip(gc);
-	chip = container_of(mm_gc, struct altera_gpio_chip, mmchip);
+	chip = gpiochip_get_data(gc);
 
 	spin_lock_irqsave(&chip->gpio_lock, flags);
 	data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA);
@@ -165,7 +160,7 @@
 	unsigned int gpio_ddr;
 
 	mm_gc = to_of_mm_gpio_chip(gc);
-	chip = container_of(mm_gc, struct altera_gpio_chip, mmchip);
+	chip = gpiochip_get_data(gc);
 
 	spin_lock_irqsave(&chip->gpio_lock, flags);
 	/* Set pin as input, assumes software controlled IP */
@@ -186,7 +181,7 @@
 	unsigned int data_reg, gpio_ddr;
 
 	mm_gc = to_of_mm_gpio_chip(gc);
-	chip = container_of(mm_gc, struct altera_gpio_chip, mmchip);
+	chip = gpiochip_get_data(gc);
 
 	spin_lock_irqsave(&chip->gpio_lock, flags);
 	/* Sets the GPIO value */
@@ -215,7 +210,7 @@
 	unsigned long status;
 	int i;
 
-	altera_gc = to_altera(irq_desc_get_handler_data(desc));
+	altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc));
 	chip = irq_desc_get_chip(desc);
 	mm_gc = &altera_gc->mmchip;
 	irqdomain = altera_gc->mmchip.gc.irqdomain;
@@ -244,7 +239,7 @@
 	unsigned long status;
 	int i;
 
-	altera_gc = to_altera(irq_desc_get_handler_data(desc));
+	altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc));
 	chip = irq_desc_get_chip(desc);
 	mm_gc = &altera_gc->mmchip;
 	irqdomain = altera_gc->mmchip.gc.irqdomain;
@@ -290,9 +285,9 @@
 	altera_gc->mmchip.gc.get		= altera_gpio_get;
 	altera_gc->mmchip.gc.set		= altera_gpio_set;
 	altera_gc->mmchip.gc.owner		= THIS_MODULE;
-	altera_gc->mmchip.gc.dev		= &pdev->dev;
+	altera_gc->mmchip.gc.parent		= &pdev->dev;
 
-	ret = of_mm_gpiochip_add(node, &altera_gc->mmchip);
+	ret = of_mm_gpiochip_add_data(node, &altera_gc->mmchip, altera_gc);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n");
 		return ret;
diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c
index d00d8192..c7040ff 100644
--- a/drivers/gpio/gpio-amd8111.c
+++ b/drivers/gpio/gpio-amd8111.c
@@ -75,11 +75,9 @@
 	u8			orig[32];
 };
 
-#define to_agp(chip)	container_of(chip, struct amd_gpio, chip)
-
 static int amd_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
-	struct amd_gpio *agp = to_agp(chip);
+	struct amd_gpio *agp = gpiochip_get_data(chip);
 
 	agp->orig[offset] = ioread8(agp->pm + AMD_REG_GPIO(offset)) &
 		(AMD_GPIO_DEBOUNCE | AMD_GPIO_MODE_MASK | AMD_GPIO_X_MASK);
@@ -91,7 +89,7 @@
 
 static void amd_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
-	struct amd_gpio *agp = to_agp(chip);
+	struct amd_gpio *agp = gpiochip_get_data(chip);
 
 	dev_dbg(&agp->pdev->dev, "Freed gpio %d, data %x\n", offset, agp->orig[offset]);
 
@@ -100,7 +98,7 @@
 
 static void amd_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct amd_gpio *agp = to_agp(chip);
+	struct amd_gpio *agp = gpiochip_get_data(chip);
 	u8 temp;
 	unsigned long flags;
 
@@ -115,7 +113,7 @@
 
 static int amd_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct amd_gpio *agp = to_agp(chip);
+	struct amd_gpio *agp = gpiochip_get_data(chip);
 	u8 temp;
 
 	temp = ioread8(agp->pm + AMD_REG_GPIO(offset));
@@ -127,7 +125,7 @@
 
 static int amd_gpio_dirout(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct amd_gpio *agp = to_agp(chip);
+	struct amd_gpio *agp = gpiochip_get_data(chip);
 	u8 temp;
 	unsigned long flags;
 
@@ -144,7 +142,7 @@
 
 static int amd_gpio_dirin(struct gpio_chip *chip, unsigned offset)
 {
-	struct amd_gpio *agp = to_agp(chip);
+	struct amd_gpio *agp = gpiochip_get_data(chip);
 	u8 temp;
 	unsigned long flags;
 
@@ -220,12 +218,12 @@
 		goto out;
 	}
 	gp.pdev = pdev;
-	gp.chip.dev = &pdev->dev;
+	gp.chip.parent = &pdev->dev;
 
 	spin_lock_init(&gp.lock);
 
 	printk(KERN_INFO "AMD-8111 GPIO detected\n");
-	err = gpiochip_add(&gp.chip);
+	err = gpiochip_add_data(&gp.chip, &gp);
 	if (err) {
 		printk(KERN_ERR "GPIO registering failed (%d)\n",
 		       err);
diff --git a/drivers/gpio/gpio-amdpt.c b/drivers/gpio/gpio-amdpt.c
index cbbb966..c248404 100644
--- a/drivers/gpio/gpio-amdpt.c
+++ b/drivers/gpio/gpio-amdpt.c
@@ -31,22 +31,20 @@
 	spinlock_t               lock;
 };
 
-#define to_pt_gpio(c)	container_of(c, struct pt_gpio_chip, gc)
-
 static int pt_gpio_request(struct gpio_chip *gc, unsigned offset)
 {
-	struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
+	struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
 	unsigned long flags;
 	u32 using_pins;
 
-	dev_dbg(gc->dev, "pt_gpio_request offset=%x\n", offset);
+	dev_dbg(gc->parent, "pt_gpio_request offset=%x\n", offset);
 
 	spin_lock_irqsave(&pt_gpio->lock, flags);
 
 	using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG);
 	if (using_pins & BIT(offset)) {
-		dev_warn(gc->dev, "PT GPIO pin %x reconfigured\n",
-			offset);
+		dev_warn(gc->parent, "PT GPIO pin %x reconfigured\n",
+			 offset);
 		spin_unlock_irqrestore(&pt_gpio->lock, flags);
 		return -EINVAL;
 	}
@@ -60,7 +58,7 @@
 
 static void pt_gpio_free(struct gpio_chip *gc, unsigned offset)
 {
-	struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
+	struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
 	unsigned long flags;
 	u32 using_pins;
 
@@ -72,16 +70,16 @@
 
 	spin_unlock_irqrestore(&pt_gpio->lock, flags);
 
-	dev_dbg(gc->dev, "pt_gpio_free offset=%x\n", offset);
+	dev_dbg(gc->parent, "pt_gpio_free offset=%x\n", offset);
 }
 
 static void pt_gpio_set_value(struct gpio_chip *gc, unsigned offset, int value)
 {
-	struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
+	struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
 	unsigned long flags;
 	u32 data;
 
-	dev_dbg(gc->dev, "pt_gpio_set_value offset=%x, value=%x\n",
+	dev_dbg(gc->parent, "pt_gpio_set_value offset=%x, value=%x\n",
 		offset, value);
 
 	spin_lock_irqsave(&pt_gpio->lock, flags);
@@ -97,7 +95,7 @@
 
 static int pt_gpio_get_value(struct gpio_chip *gc, unsigned offset)
 {
-	struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
+	struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
 	unsigned long flags;
 	u32 data;
 
@@ -116,7 +114,7 @@
 	data >>= offset;
 	data &= 1;
 
-	dev_dbg(gc->dev, "pt_gpio_get_value offset=%x, value=%x\n",
+	dev_dbg(gc->parent, "pt_gpio_get_value offset=%x, value=%x\n",
 		offset, data);
 
 	return data;
@@ -124,11 +122,11 @@
 
 static int pt_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
 {
-	struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
+	struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
 	unsigned long flags;
 	u32 data;
 
-	dev_dbg(gc->dev, "pt_gpio_dirction_input offset=%x\n", offset);
+	dev_dbg(gc->parent, "pt_gpio_dirction_input offset=%x\n", offset);
 
 	spin_lock_irqsave(&pt_gpio->lock, flags);
 
@@ -144,11 +142,11 @@
 static int pt_gpio_direction_output(struct gpio_chip *gc,
 					unsigned offset, int value)
 {
-	struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
+	struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
 	unsigned long flags;
 	u32 data;
 
-	dev_dbg(gc->dev, "pt_gpio_direction_output offset=%x, value=%x\n",
+	dev_dbg(gc->parent, "pt_gpio_direction_output offset=%x, value=%x\n",
 		offset, value);
 
 	spin_lock_irqsave(&pt_gpio->lock, flags);
@@ -202,7 +200,7 @@
 
 	pt_gpio->gc.label            = pdev->name;
 	pt_gpio->gc.owner            = THIS_MODULE;
-	pt_gpio->gc.dev              = dev;
+	pt_gpio->gc.parent              = dev;
 	pt_gpio->gc.request          = pt_gpio_request;
 	pt_gpio->gc.free             = pt_gpio_free;
 	pt_gpio->gc.direction_input  = pt_gpio_direction_input;
@@ -214,7 +212,7 @@
 #if defined(CONFIG_OF_GPIO)
 	pt_gpio->gc.of_node          = pdev->dev.of_node;
 #endif
-	ret = gpiochip_add(&pt_gpio->gc);
+	ret = gpiochip_add_data(&pt_gpio->gc, pt_gpio);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register GPIO lib\n");
 		return ret;
diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c
index 624ea54..e910c1f 100644
--- a/drivers/gpio/gpio-arizona.c
+++ b/drivers/gpio/gpio-arizona.c
@@ -28,14 +28,9 @@
 	struct gpio_chip gpio_chip;
 };
 
-static inline struct arizona_gpio *to_arizona_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct arizona_gpio, gpio_chip);
-}
-
 static int arizona_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
-	struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip);
+	struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
 	struct arizona *arizona = arizona_gpio->arizona;
 
 	return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
@@ -44,7 +39,7 @@
 
 static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip);
+	struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
 	struct arizona *arizona = arizona_gpio->arizona;
 	unsigned int val;
 	int ret;
@@ -62,7 +57,7 @@
 static int arizona_gpio_direction_out(struct gpio_chip *chip,
 				     unsigned offset, int value)
 {
-	struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip);
+	struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
 	struct arizona *arizona = arizona_gpio->arizona;
 
 	if (value)
@@ -74,7 +69,7 @@
 
 static void arizona_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct arizona_gpio *arizona_gpio = to_arizona_gpio(chip);
+	struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
 	struct arizona *arizona = arizona_gpio->arizona;
 
 	if (value)
@@ -108,7 +103,7 @@
 
 	arizona_gpio->arizona = arizona;
 	arizona_gpio->gpio_chip = template_chip;
-	arizona_gpio->gpio_chip.dev = &pdev->dev;
+	arizona_gpio->gpio_chip.parent = &pdev->dev;
 #ifdef CONFIG_OF_GPIO
 	arizona_gpio->gpio_chip.of_node = arizona->dev->of_node;
 #endif
@@ -137,7 +132,7 @@
 	else
 		arizona_gpio->gpio_chip.base = -1;
 
-	ret = gpiochip_add(&arizona_gpio->gpio_chip);
+	ret = gpiochip_add_data(&arizona_gpio->gpio_chip, arizona_gpio);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
 			ret);
diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index 5eaea8b..d13dd13 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -24,12 +24,10 @@
 	spinlock_t lock;
 };
 
-#define to_ath79_gpio_ctrl(c) container_of(c, struct ath79_gpio_ctrl, chip)
-
 static void ath79_gpio_set_value(struct gpio_chip *chip,
 				unsigned gpio, int value)
 {
-	struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
+	struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
 
 	if (value)
 		__raw_writel(BIT(gpio), ctrl->base + AR71XX_GPIO_REG_SET);
@@ -39,7 +37,7 @@
 
 static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
 {
-	struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
+	struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
 
 	return (__raw_readl(ctrl->base + AR71XX_GPIO_REG_IN) >> gpio) & 1;
 }
@@ -47,7 +45,7 @@
 static int ath79_gpio_direction_input(struct gpio_chip *chip,
 				       unsigned offset)
 {
-	struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
+	struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
 	unsigned long flags;
 
 	spin_lock_irqsave(&ctrl->lock, flags);
@@ -64,7 +62,7 @@
 static int ath79_gpio_direction_output(struct gpio_chip *chip,
 					unsigned offset, int value)
 {
-	struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
+	struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
 	unsigned long flags;
 
 	spin_lock_irqsave(&ctrl->lock, flags);
@@ -85,7 +83,7 @@
 
 static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
+	struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
 	unsigned long flags;
 
 	spin_lock_irqsave(&ctrl->lock, flags);
@@ -102,7 +100,7 @@
 static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 					int value)
 {
-	struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
+	struct ath79_gpio_ctrl *ctrl = gpiochip_get_data(chip);
 	unsigned long flags;
 
 	spin_lock_irqsave(&ctrl->lock, flags);
@@ -138,7 +136,7 @@
 
 static int ath79_gpio_probe(struct platform_device *pdev)
 {
-	struct ath79_gpio_platform_data *pdata = pdev->dev.platform_data;
+	struct ath79_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct device_node *np = pdev->dev.of_node;
 	struct ath79_gpio_ctrl *ctrl;
 	struct resource *res;
@@ -177,14 +175,14 @@
 
 	spin_lock_init(&ctrl->lock);
 	memcpy(&ctrl->chip, &ath79_gpio_chip, sizeof(ctrl->chip));
-	ctrl->chip.dev = &pdev->dev;
+	ctrl->chip.parent = &pdev->dev;
 	ctrl->chip.ngpio = ath79_gpio_count;
 	if (oe_inverted) {
 		ctrl->chip.direction_input = ar934x_gpio_direction_input;
 		ctrl->chip.direction_output = ar934x_gpio_direction_output;
 	}
 
-	err = gpiochip_add(&ctrl->chip);
+	err = gpiochip_add_data(&ctrl->chip, ctrl);
 	if (err) {
 		dev_err(&pdev->dev,
 			"cannot add AR71xx GPIO chip, error=%d", err);
diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c
index 33a1f97..b6c5abe 100644
--- a/drivers/gpio/gpio-bcm-kona.c
+++ b/drivers/gpio/gpio-bcm-kona.c
@@ -78,11 +78,6 @@
 	struct bcm_kona_gpio *kona_gpio;
 };
 
-static inline struct bcm_kona_gpio *to_kona_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct bcm_kona_gpio, gpio_chip);
-}
-
 static inline void bcm_kona_gpio_write_lock_regs(void __iomem *reg_base,
 						int bank_id, u32 lockcode)
 {
@@ -124,7 +119,7 @@
 
 static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio)
 {
-	struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip);
+	struct bcm_kona_gpio *kona_gpio = gpiochip_get_data(chip);
 	void __iomem *reg_base = kona_gpio->reg_base;
 	u32 val;
 
@@ -141,7 +136,7 @@
 	u32 val, reg_offset;
 	unsigned long flags;
 
-	kona_gpio = to_kona_gpio(chip);
+	kona_gpio = gpiochip_get_data(chip);
 	reg_base = kona_gpio->reg_base;
 	spin_lock_irqsave(&kona_gpio->lock, flags);
 
@@ -168,7 +163,7 @@
 	u32 val, reg_offset;
 	unsigned long flags;
 
-	kona_gpio = to_kona_gpio(chip);
+	kona_gpio = gpiochip_get_data(chip);
 	reg_base = kona_gpio->reg_base;
 	spin_lock_irqsave(&kona_gpio->lock, flags);
 
@@ -188,7 +183,7 @@
 
 static int bcm_kona_gpio_request(struct gpio_chip *chip, unsigned gpio)
 {
-	struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip);
+	struct bcm_kona_gpio *kona_gpio = gpiochip_get_data(chip);
 
 	bcm_kona_gpio_unlock_gpio(kona_gpio, gpio);
 	return 0;
@@ -196,7 +191,7 @@
 
 static void bcm_kona_gpio_free(struct gpio_chip *chip, unsigned gpio)
 {
-	struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip);
+	struct bcm_kona_gpio *kona_gpio = gpiochip_get_data(chip);
 
 	bcm_kona_gpio_lock_gpio(kona_gpio, gpio);
 }
@@ -208,7 +203,7 @@
 	u32 val;
 	unsigned long flags;
 
-	kona_gpio = to_kona_gpio(chip);
+	kona_gpio = gpiochip_get_data(chip);
 	reg_base = kona_gpio->reg_base;
 	spin_lock_irqsave(&kona_gpio->lock, flags);
 
@@ -232,7 +227,7 @@
 	u32 val, reg_offset;
 	unsigned long flags;
 
-	kona_gpio = to_kona_gpio(chip);
+	kona_gpio = gpiochip_get_data(chip);
 	reg_base = kona_gpio->reg_base;
 	spin_lock_irqsave(&kona_gpio->lock, flags);
 
@@ -255,7 +250,7 @@
 {
 	struct bcm_kona_gpio *kona_gpio;
 
-	kona_gpio = to_kona_gpio(chip);
+	kona_gpio = gpiochip_get_data(chip);
 	if (gpio >= kona_gpio->gpio_chip.ngpio)
 		return -ENXIO;
 	return irq_create_mapping(kona_gpio->irq_domain, gpio);
@@ -269,11 +264,11 @@
 	u32 val, res;
 	unsigned long flags;
 
-	kona_gpio = to_kona_gpio(chip);
+	kona_gpio = gpiochip_get_data(chip);
 	reg_base = kona_gpio->reg_base;
 	/* debounce must be 1-128ms (or 0) */
 	if ((debounce > 0 && debounce < 1000) || debounce > 128000) {
-		dev_err(chip->dev, "Debounce value %u not in range\n",
+		dev_err(chip->parent, "Debounce value %u not in range\n",
 			debounce);
 		return -EINVAL;
 	}
@@ -416,7 +411,7 @@
 	case IRQ_TYPE_LEVEL_LOW:
 		/* BCM GPIO doesn't support level triggering */
 	default:
-		dev_err(kona_gpio->gpio_chip.dev,
+		dev_err(kona_gpio->gpio_chip.parent,
 			"Invalid BCM GPIO irq type 0x%x\n", type);
 		return -EINVAL;
 	}
@@ -477,7 +472,7 @@
 	struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
 
 	if (gpiochip_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) {
-		dev_err(kona_gpio->gpio_chip.dev,
+		dev_err(kona_gpio->gpio_chip.parent,
 			"unable to lock HW IRQ %lu for IRQ\n",
 			d->hwirq);
 		return -EINVAL;
@@ -635,7 +630,7 @@
 
 	bcm_kona_gpio_reset(kona_gpio);
 
-	ret = gpiochip_add(chip);
+	ret = gpiochip_add_data(chip, kona_gpio);
 	if (ret < 0) {
 		dev_err(dev, "Couldn't add GPIO chip -- %d\n", ret);
 		goto err_irq_domain;
diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c
index 4c64627..d764425 100644
--- a/drivers/gpio/gpio-brcmstb.c
+++ b/drivers/gpio/gpio-brcmstb.c
@@ -16,7 +16,6 @@
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
 #include <linux/module.h>
-#include <linux/basic_mmio_gpio.h>
 #include <linux/irqdomain.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/interrupt.h>
@@ -35,7 +34,7 @@
 struct brcmstb_gpio_bank {
 	struct list_head node;
 	int id;
-	struct bgpio_chip bgc;
+	struct gpio_chip gc;
 	struct brcmstb_gpio_priv *parent_priv;
 	u32 width;
 	struct irq_chip irq_chip;
@@ -57,37 +56,30 @@
 /* assumes MAX_GPIO_PER_BANK is a multiple of 2 */
 #define GPIO_BIT(gpio)          ((gpio) & (MAX_GPIO_PER_BANK - 1))
 
-static inline struct brcmstb_gpio_bank *
-brcmstb_gpio_gc_to_bank(struct gpio_chip *gc)
-{
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-	return container_of(bgc, struct brcmstb_gpio_bank, bgc);
-}
-
 static inline struct brcmstb_gpio_priv *
 brcmstb_gpio_gc_to_priv(struct gpio_chip *gc)
 {
-	struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
+	struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
 	return bank->parent_priv;
 }
 
 static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank,
 		unsigned int offset, bool enable)
 {
-	struct bgpio_chip *bgc = &bank->bgc;
+	struct gpio_chip *gc = &bank->gc;
 	struct brcmstb_gpio_priv *priv = bank->parent_priv;
-	u32 mask = bgc->pin2mask(bgc, offset);
+	u32 mask = gc->pin2mask(gc, offset);
 	u32 imask;
 	unsigned long flags;
 
-	spin_lock_irqsave(&bgc->lock, flags);
-	imask = bgc->read_reg(priv->reg_base + GIO_MASK(bank->id));
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
+	imask = gc->read_reg(priv->reg_base + GIO_MASK(bank->id));
 	if (enable)
 		imask |= mask;
 	else
 		imask &= ~mask;
-	bgc->write_reg(priv->reg_base + GIO_MASK(bank->id), imask);
-	spin_unlock_irqrestore(&bgc->lock, flags);
+	gc->write_reg(priv->reg_base + GIO_MASK(bank->id), imask);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 }
 
 /* -------------------- IRQ chip functions -------------------- */
@@ -95,7 +87,7 @@
 static void brcmstb_gpio_irq_mask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
+	struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
 
 	brcmstb_gpio_set_imask(bank, d->hwirq, false);
 }
@@ -103,7 +95,7 @@
 static void brcmstb_gpio_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
+	struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
 
 	brcmstb_gpio_set_imask(bank, d->hwirq, true);
 }
@@ -111,7 +103,7 @@
 static int brcmstb_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
+	struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
 	struct brcmstb_gpio_priv *priv = bank->parent_priv;
 	u32 mask = BIT(d->hwirq);
 	u32 edge_insensitive, iedge_insensitive;
@@ -149,23 +141,23 @@
 		return -EINVAL;
 	}
 
-	spin_lock_irqsave(&bank->bgc.lock, flags);
+	spin_lock_irqsave(&bank->gc.bgpio_lock, flags);
 
-	iedge_config = bank->bgc.read_reg(priv->reg_base +
+	iedge_config = bank->gc.read_reg(priv->reg_base +
 			GIO_EC(bank->id)) & ~mask;
-	iedge_insensitive = bank->bgc.read_reg(priv->reg_base +
+	iedge_insensitive = bank->gc.read_reg(priv->reg_base +
 			GIO_EI(bank->id)) & ~mask;
-	ilevel = bank->bgc.read_reg(priv->reg_base +
+	ilevel = bank->gc.read_reg(priv->reg_base +
 			GIO_LEVEL(bank->id)) & ~mask;
 
-	bank->bgc.write_reg(priv->reg_base + GIO_EC(bank->id),
+	bank->gc.write_reg(priv->reg_base + GIO_EC(bank->id),
 			iedge_config | edge_config);
-	bank->bgc.write_reg(priv->reg_base + GIO_EI(bank->id),
+	bank->gc.write_reg(priv->reg_base + GIO_EI(bank->id),
 			iedge_insensitive | edge_insensitive);
-	bank->bgc.write_reg(priv->reg_base + GIO_LEVEL(bank->id),
+	bank->gc.write_reg(priv->reg_base + GIO_LEVEL(bank->id),
 			ilevel | level);
 
-	spin_unlock_irqrestore(&bank->bgc.lock, flags);
+	spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags);
 	return 0;
 }
 
@@ -210,29 +202,29 @@
 static void brcmstb_gpio_irq_bank_handler(struct brcmstb_gpio_bank *bank)
 {
 	struct brcmstb_gpio_priv *priv = bank->parent_priv;
-	struct irq_domain *irq_domain = bank->bgc.gc.irqdomain;
+	struct irq_domain *irq_domain = bank->gc.irqdomain;
 	void __iomem *reg_base = priv->reg_base;
 	unsigned long status;
 	unsigned long flags;
 
-	spin_lock_irqsave(&bank->bgc.lock, flags);
-	while ((status = bank->bgc.read_reg(reg_base + GIO_STAT(bank->id)) &
-			 bank->bgc.read_reg(reg_base + GIO_MASK(bank->id)))) {
+	spin_lock_irqsave(&bank->gc.bgpio_lock, flags);
+	while ((status = bank->gc.read_reg(reg_base + GIO_STAT(bank->id)) &
+			 bank->gc.read_reg(reg_base + GIO_MASK(bank->id)))) {
 		int bit;
 
 		for_each_set_bit(bit, &status, 32) {
-			u32 stat = bank->bgc.read_reg(reg_base +
+			u32 stat = bank->gc.read_reg(reg_base +
 						      GIO_STAT(bank->id));
 			if (bit >= bank->width)
 				dev_warn(&priv->pdev->dev,
 					 "IRQ for invalid GPIO (bank=%d, offset=%d)\n",
 					 bank->id, bit);
-			bank->bgc.write_reg(reg_base + GIO_STAT(bank->id),
+			bank->gc.write_reg(reg_base + GIO_STAT(bank->id),
 					    stat | BIT(bit));
 			generic_handle_irq(irq_find_mapping(irq_domain, bit));
 		}
 	}
-	spin_unlock_irqrestore(&bank->bgc.lock, flags);
+	spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags);
 }
 
 /* Each UPG GIO block has one IRQ for all banks */
@@ -303,9 +295,7 @@
 	 */
 	list_for_each(pos, &priv->bank_list) {
 		bank = list_entry(pos, struct brcmstb_gpio_bank, node);
-		ret = bgpio_remove(&bank->bgc);
-		if (ret)
-			dev_err(&pdev->dev, "gpiochip_remove fail in cleanup\n");
+		gpiochip_remove(&bank->gc);
 	}
 	if (priv->reboot_notifier.notifier_call) {
 		ret = unregister_reboot_notifier(&priv->reboot_notifier);
@@ -320,7 +310,7 @@
 		const struct of_phandle_args *gpiospec, u32 *flags)
 {
 	struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc);
-	struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
+	struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
 	int offset;
 
 	if (gc->of_gpio_n_cells != 2) {
@@ -398,9 +388,9 @@
 	if (priv->can_wake)
 		bank->irq_chip.irq_set_wake = brcmstb_gpio_irq_set_wake;
 
-	gpiochip_irqchip_add(&bank->bgc.gc, &bank->irq_chip, 0,
+	gpiochip_irqchip_add(&bank->gc, &bank->irq_chip, 0,
 			handle_simple_irq, IRQ_TYPE_NONE);
-	gpiochip_set_chained_irqchip(&bank->bgc.gc, &bank->irq_chip,
+	gpiochip_set_chained_irqchip(&bank->gc, &bank->irq_chip,
 			priv->parent_irq, brcmstb_gpio_irq_handler);
 
 	return 0;
@@ -419,6 +409,7 @@
 	int num_banks = 0;
 	int err;
 	static int gpio_base;
+	unsigned long flags = 0;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
@@ -448,10 +439,21 @@
 	if (brcmstb_gpio_sanity_check_banks(dev, np, res))
 		return -EINVAL;
 
+	/*
+	 * MIPS endianness is configured by boot strap, which also reverses all
+	 * bus endianness (i.e., big-endian CPU + big endian bus ==> native
+	 * endian I/O).
+	 *
+	 * Other architectures (e.g., ARM) either do not support big endian, or
+	 * else leave I/O in little endian mode.
+	 */
+#if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN)
+	flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER;
+#endif
+
 	of_property_for_each_u32(np, "brcm,gpio-bank-widths", prop, p,
 			bank_width) {
 		struct brcmstb_gpio_bank *bank;
-		struct bgpio_chip *bgc;
 		struct gpio_chip *gc;
 
 		bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
@@ -473,17 +475,16 @@
 		 * Regs are 4 bytes wide, have data reg, no set/clear regs,
 		 * and direction bits have 0 = output and 1 = input
 		 */
-		bgc = &bank->bgc;
-		err = bgpio_init(bgc, dev, 4,
+		gc = &bank->gc;
+		err = bgpio_init(gc, dev, 4,
 				reg_base + GIO_DATA(bank->id),
 				NULL, NULL, NULL,
-				reg_base + GIO_IODIR(bank->id), 0);
+				reg_base + GIO_IODIR(bank->id), flags);
 		if (err) {
 			dev_err(dev, "bgpio_init() failed\n");
 			goto fail;
 		}
 
-		gc = &bgc->gc;
 		gc->of_node = np;
 		gc->owner = THIS_MODULE;
 		gc->label = np->full_name;
@@ -497,9 +498,9 @@
 		 * Mask all interrupts by default, since wakeup interrupts may
 		 * be retained from S5 cold boot
 		 */
-		bank->bgc.write_reg(reg_base + GIO_MASK(bank->id), 0);
+		gc->write_reg(reg_base + GIO_MASK(bank->id), 0);
 
-		err = gpiochip_add(gc);
+		err = gpiochip_add_data(gc, bank);
 		if (err) {
 			dev_err(dev, "Could not add gpiochip for bank %d\n",
 					bank->id);
diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c
index 7e4c43c..acefb25 100644
--- a/drivers/gpio/gpio-bt8xx.c
+++ b/drivers/gpio/gpio-bt8xx.c
@@ -80,7 +80,7 @@
 
 static int bt8xxgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
 {
-	struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
+	struct bt8xxgpio *bg = gpiochip_get_data(gpio);
 	unsigned long flags;
 	u32 outen, data;
 
@@ -101,7 +101,7 @@
 
 static int bt8xxgpio_gpio_get(struct gpio_chip *gpio, unsigned nr)
 {
-	struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
+	struct bt8xxgpio *bg = gpiochip_get_data(gpio);
 	unsigned long flags;
 	u32 val;
 
@@ -115,7 +115,7 @@
 static int bt8xxgpio_gpio_direction_output(struct gpio_chip *gpio,
 					unsigned nr, int val)
 {
-	struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
+	struct bt8xxgpio *bg = gpiochip_get_data(gpio);
 	unsigned long flags;
 	u32 outen, data;
 
@@ -140,7 +140,7 @@
 static void bt8xxgpio_gpio_set(struct gpio_chip *gpio,
 			    unsigned nr, int val)
 {
-	struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
+	struct bt8xxgpio *bg = gpiochip_get_data(gpio);
 	unsigned long flags;
 	u32 data;
 
@@ -217,7 +217,7 @@
 	bgwrite(0, BT848_GPIO_OUT_EN);
 
 	bt8xxgpio_gpio_setup(bg);
-	err = gpiochip_add(&bg->gpio);
+	err = gpiochip_add_data(&bg->gpio, bg);
 	if (err) {
 		printk(KERN_ERR "bt8xxgpio: Failed to register GPIOs\n");
 		goto err_disable;
diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c
index b6908f1..c84f955 100644
--- a/drivers/gpio/gpio-clps711x.c
+++ b/drivers/gpio/gpio-clps711x.c
@@ -10,24 +10,23 @@
  */
 
 #include <linux/err.h>
-#include <linux/gpio.h>
 #include <linux/module.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/platform_device.h>
 
 static int clps711x_gpio_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
 	void __iomem *dat, *dir;
-	struct bgpio_chip *bgc;
+	struct gpio_chip *gc;
 	struct resource *res;
 	int err, id = np ? of_alias_get_id(np, "gpio") : pdev->id;
 
 	if ((id < 0) || (id > 4))
 		return -ENODEV;
 
-	bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
-	if (!bgc)
+	gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
+	if (!gc)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -43,11 +42,11 @@
 	switch (id) {
 	case 3:
 		/* PORTD is inverted logic for direction register */
-		err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL,
+		err = bgpio_init(gc, &pdev->dev, 1, dat, NULL, NULL,
 				 NULL, dir, 0);
 		break;
 	default:
-		err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL,
+		err = bgpio_init(gc, &pdev->dev, 1, dat, NULL, NULL,
 				 dir, NULL, 0);
 		break;
 	}
@@ -58,24 +57,25 @@
 	switch (id) {
 	case 4:
 		/* PORTE is 3 lines only */
-		bgc->gc.ngpio = 3;
+		gc->ngpio = 3;
 		break;
 	default:
 		break;
 	}
 
-	bgc->gc.base = id * 8;
-	bgc->gc.owner = THIS_MODULE;
-	platform_set_drvdata(pdev, bgc);
+	gc->base = id * 8;
+	gc->owner = THIS_MODULE;
+	platform_set_drvdata(pdev, gc);
 
-	return gpiochip_add(&bgc->gc);
+	return gpiochip_add_data(gc, NULL);
 }
 
 static int clps711x_gpio_remove(struct platform_device *pdev)
 {
-	struct bgpio_chip *bgc = platform_get_drvdata(pdev);
+	struct gpio_chip *gc = platform_get_drvdata(pdev);
 
-	return bgpio_remove(bgc);
+	gpiochip_remove(gc);
+	return 0;
 }
 
 static const struct of_device_id __maybe_unused clps711x_gpio_ids[] = {
diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c
index fddd204..7865ef0 100644
--- a/drivers/gpio/gpio-crystalcove.c
+++ b/drivers/gpio/gpio-crystalcove.c
@@ -86,11 +86,6 @@
 	bool set_irq_mask;
 };
 
-static inline struct crystalcove_gpio *to_cg(struct gpio_chip *gc)
-{
-	return container_of(gc, struct crystalcove_gpio, chip);
-}
-
 static inline int to_reg(int gpio, enum ctrl_register reg_type)
 {
 	int reg;
@@ -134,7 +129,7 @@
 
 static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
 {
-	struct crystalcove_gpio *cg = to_cg(chip);
+	struct crystalcove_gpio *cg = gpiochip_get_data(chip);
 
 	if (gpio > CRYSTALCOVE_VGPIO_NUM)
 		return 0;
@@ -146,7 +141,7 @@
 static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio,
 				    int value)
 {
-	struct crystalcove_gpio *cg = to_cg(chip);
+	struct crystalcove_gpio *cg = gpiochip_get_data(chip);
 
 	if (gpio > CRYSTALCOVE_VGPIO_NUM)
 		return 0;
@@ -157,7 +152,7 @@
 
 static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio)
 {
-	struct crystalcove_gpio *cg = to_cg(chip);
+	struct crystalcove_gpio *cg = gpiochip_get_data(chip);
 	int ret;
 	unsigned int val;
 
@@ -174,7 +169,7 @@
 static void crystalcove_gpio_set(struct gpio_chip *chip,
 				 unsigned gpio, int value)
 {
-	struct crystalcove_gpio *cg = to_cg(chip);
+	struct crystalcove_gpio *cg = gpiochip_get_data(chip);
 
 	if (gpio > CRYSTALCOVE_VGPIO_NUM)
 		return;
@@ -187,7 +182,8 @@
 
 static int crystalcove_irq_type(struct irq_data *data, unsigned type)
 {
-	struct crystalcove_gpio *cg = to_cg(irq_data_get_irq_chip_data(data));
+	struct crystalcove_gpio *cg =
+		gpiochip_get_data(irq_data_get_irq_chip_data(data));
 
 	switch (type) {
 	case IRQ_TYPE_NONE:
@@ -213,14 +209,16 @@
 
 static void crystalcove_bus_lock(struct irq_data *data)
 {
-	struct crystalcove_gpio *cg = to_cg(irq_data_get_irq_chip_data(data));
+	struct crystalcove_gpio *cg =
+		gpiochip_get_data(irq_data_get_irq_chip_data(data));
 
 	mutex_lock(&cg->buslock);
 }
 
 static void crystalcove_bus_sync_unlock(struct irq_data *data)
 {
-	struct crystalcove_gpio *cg = to_cg(irq_data_get_irq_chip_data(data));
+	struct crystalcove_gpio *cg =
+		gpiochip_get_data(irq_data_get_irq_chip_data(data));
 	int gpio = data->hwirq;
 
 	if (cg->update & UPDATE_IRQ_TYPE)
@@ -234,7 +232,8 @@
 
 static void crystalcove_irq_unmask(struct irq_data *data)
 {
-	struct crystalcove_gpio *cg = to_cg(irq_data_get_irq_chip_data(data));
+	struct crystalcove_gpio *cg =
+		gpiochip_get_data(irq_data_get_irq_chip_data(data));
 
 	cg->set_irq_mask = false;
 	cg->update |= UPDATE_IRQ_MASK;
@@ -242,7 +241,8 @@
 
 static void crystalcove_irq_mask(struct irq_data *data)
 {
-	struct crystalcove_gpio *cg = to_cg(irq_data_get_irq_chip_data(data));
+	struct crystalcove_gpio *cg =
+		gpiochip_get_data(irq_data_get_irq_chip_data(data));
 
 	cg->set_irq_mask = true;
 	cg->update |= UPDATE_IRQ_MASK;
@@ -288,7 +288,7 @@
 static void crystalcove_gpio_dbg_show(struct seq_file *s,
 				      struct gpio_chip *chip)
 {
-	struct crystalcove_gpio *cg = to_cg(chip);
+	struct crystalcove_gpio *cg = gpiochip_get_data(chip);
 	int gpio, offset;
 	unsigned int ctlo, ctli, mirqs0, mirqsx, irq;
 
@@ -341,11 +341,11 @@
 	cg->chip.base = -1;
 	cg->chip.ngpio = CRYSTALCOVE_VGPIO_NUM;
 	cg->chip.can_sleep = true;
-	cg->chip.dev = dev;
+	cg->chip.parent = dev;
 	cg->chip.dbg_show = crystalcove_gpio_dbg_show;
 	cg->regmap = pmic->regmap;
 
-	retval = gpiochip_add(&cg->chip);
+	retval = gpiochip_add_data(&cg->chip, cg);
 	if (retval) {
 		dev_warn(&pdev->dev, "add gpio chip error: %d\n", retval);
 		return retval;
diff --git a/drivers/gpio/gpio-cs5535.c b/drivers/gpio/gpio-cs5535.c
index 7b0b198..eccb712 100644
--- a/drivers/gpio/gpio-cs5535.c
+++ b/drivers/gpio/gpio-cs5535.c
@@ -42,6 +42,10 @@
 module_param_named(mask, mask, ulong, 0444);
 MODULE_PARM_DESC(mask, "GPIO channel mask.");
 
+/*
+ * FIXME: convert this singleton driver to use the state container
+ * design pattern, see Documentation/driver-model/design-patterns.txt
+ */
 static struct cs5535_gpio_chip {
 	struct gpio_chip chip;
 	resource_size_t base;
@@ -201,8 +205,7 @@
 
 static int chip_gpio_request(struct gpio_chip *c, unsigned offset)
 {
-	struct cs5535_gpio_chip *chip =
-		container_of(c, struct cs5535_gpio_chip, chip);
+	struct cs5535_gpio_chip *chip = gpiochip_get_data(c);
 	unsigned long flags;
 
 	spin_lock_irqsave(&chip->lock, flags);
@@ -242,8 +245,7 @@
 
 static int chip_direction_input(struct gpio_chip *c, unsigned offset)
 {
-	struct cs5535_gpio_chip *chip =
-		container_of(c, struct cs5535_gpio_chip, chip);
+	struct cs5535_gpio_chip *chip = gpiochip_get_data(c);
 	unsigned long flags;
 
 	spin_lock_irqsave(&chip->lock, flags);
@@ -256,8 +258,7 @@
 
 static int chip_direction_output(struct gpio_chip *c, unsigned offset, int val)
 {
-	struct cs5535_gpio_chip *chip =
-		container_of(c, struct cs5535_gpio_chip, chip);
+	struct cs5535_gpio_chip *chip = gpiochip_get_data(c);
 	unsigned long flags;
 
 	spin_lock_irqsave(&chip->lock, flags);
@@ -347,7 +348,7 @@
 				mask_orig, mask);
 
 	/* finally, register with the generic GPIO API */
-	err = gpiochip_add(&cs5535_gpio_chip.chip);
+	err = gpiochip_add_data(&cs5535_gpio_chip.chip, &cs5535_gpio_chip);
 	if (err)
 		goto done;
 
diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c
index 2e9578e..f9b3247 100644
--- a/drivers/gpio/gpio-da9052.c
+++ b/drivers/gpio/gpio-da9052.c
@@ -51,11 +51,6 @@
 	struct gpio_chip gp;
 };
 
-static inline struct da9052_gpio *to_da9052_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct da9052_gpio, gp);
-}
-
 static unsigned char da9052_gpio_port_odd(unsigned offset)
 {
 	return offset % 2;
@@ -63,7 +58,7 @@
 
 static int da9052_gpio_get(struct gpio_chip *gc, unsigned offset)
 {
-	struct da9052_gpio *gpio = to_da9052_gpio(gc);
+	struct da9052_gpio *gpio = gpiochip_get_data(gc);
 	int da9052_port_direction = 0;
 	int ret;
 
@@ -89,15 +84,12 @@
 					      DA9052_STATUS_D_REG);
 		if (ret < 0)
 			return ret;
-		if (ret & (1 << DA9052_GPIO_SHIFT_COUNT(offset)))
-			return 1;
-		else
-			return 0;
+		return !!(ret & (1 << DA9052_GPIO_SHIFT_COUNT(offset)));
 	case DA9052_OUTPUT_PUSHPULL:
 		if (da9052_gpio_port_odd(offset))
-			return ret & DA9052_GPIO_ODD_PORT_MODE;
+			return !!(ret & DA9052_GPIO_ODD_PORT_MODE);
 		else
-			return ret & DA9052_GPIO_EVEN_PORT_MODE;
+			return !!(ret & DA9052_GPIO_EVEN_PORT_MODE);
 	default:
 		return -EINVAL;
 	}
@@ -105,7 +97,7 @@
 
 static void da9052_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
 {
-	struct da9052_gpio *gpio = to_da9052_gpio(gc);
+	struct da9052_gpio *gpio = gpiochip_get_data(gc);
 	int ret;
 
 	if (da9052_gpio_port_odd(offset)) {
@@ -131,7 +123,7 @@
 
 static int da9052_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
 {
-	struct da9052_gpio *gpio = to_da9052_gpio(gc);
+	struct da9052_gpio *gpio = gpiochip_get_data(gc);
 	unsigned char register_value;
 	int ret;
 
@@ -157,7 +149,7 @@
 static int da9052_gpio_direction_output(struct gpio_chip *gc,
 					unsigned offset, int value)
 {
-	struct da9052_gpio *gpio = to_da9052_gpio(gc);
+	struct da9052_gpio *gpio = gpiochip_get_data(gc);
 	unsigned char register_value;
 	int ret;
 
@@ -182,7 +174,7 @@
 
 static int da9052_gpio_to_irq(struct gpio_chip *gc, u32 offset)
 {
-	struct da9052_gpio *gpio = to_da9052_gpio(gc);
+	struct da9052_gpio *gpio = gpiochip_get_data(gc);
 	struct da9052 *da9052 = gpio->da9052;
 
 	int irq;
@@ -222,7 +214,7 @@
 	if (pdata && pdata->gpio_base)
 		gpio->gp.base = pdata->gpio_base;
 
-	ret = gpiochip_add(&gpio->gp);
+	ret = gpiochip_add_data(&gpio->gp, gpio);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
 		return ret;
diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c
index 7227e6e..18210fb 100644
--- a/drivers/gpio/gpio-da9055.c
+++ b/drivers/gpio/gpio-da9055.c
@@ -35,14 +35,9 @@
 	struct gpio_chip gp;
 };
 
-static inline struct da9055_gpio *to_da9055_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct da9055_gpio, gp);
-}
-
 static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset)
 {
-	struct da9055_gpio *gpio = to_da9055_gpio(gc);
+	struct da9055_gpio *gpio = gpiochip_get_data(gc);
 	int gpio_direction = 0;
 	int ret;
 
@@ -71,7 +66,7 @@
 
 static void da9055_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
 {
-	struct da9055_gpio *gpio = to_da9055_gpio(gc);
+	struct da9055_gpio *gpio = gpiochip_get_data(gc);
 
 	da9055_reg_update(gpio->da9055,
 			DA9055_REG_GPIO_MODE0_2,
@@ -81,7 +76,7 @@
 
 static int da9055_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
 {
-	struct da9055_gpio *gpio = to_da9055_gpio(gc);
+	struct da9055_gpio *gpio = gpiochip_get_data(gc);
 	unsigned char reg_byte;
 
 	reg_byte = (DA9055_ACT_LOW | DA9055_GPI)
@@ -97,7 +92,7 @@
 static int da9055_gpio_direction_output(struct gpio_chip *gc,
 					unsigned offset, int value)
 {
-	struct da9055_gpio *gpio = to_da9055_gpio(gc);
+	struct da9055_gpio *gpio = gpiochip_get_data(gc);
 	unsigned char reg_byte;
 	int ret;
 
@@ -119,7 +114,7 @@
 
 static int da9055_gpio_to_irq(struct gpio_chip *gc, u32 offset)
 {
-	struct da9055_gpio *gpio = to_da9055_gpio(gc);
+	struct da9055_gpio *gpio = gpiochip_get_data(gc);
 	struct da9055 *da9055 = gpio->da9055;
 
 	return regmap_irq_get_virq(da9055->irq_data,
@@ -156,7 +151,7 @@
 	if (pdata && pdata->gpio_base)
 		gpio->gp.base = pdata->gpio_base;
 
-	ret = gpiochip_add(&gpio->gp);
+	ret = gpiochip_add_data(&gpio->gp, gpio);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
 		goto err_mem;
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index 5e71538..ec58f42 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -41,9 +41,6 @@
 
 #define BINTEN	0x8 /* GPIO Interrupt Per-Bank Enable Register */
 
-#define chip2controller(chip)	\
-	container_of(chip, struct davinci_gpio_controller, chip)
-
 static void __iomem *gpio_base;
 
 static struct davinci_gpio_regs __iomem *gpio2regs(unsigned gpio)
@@ -82,7 +79,7 @@
 static inline int __davinci_direction(struct gpio_chip *chip,
 			unsigned offset, bool out, int value)
 {
-	struct davinci_gpio_controller *d = chip2controller(chip);
+	struct davinci_gpio_controller *d = gpiochip_get_data(chip);
 	struct davinci_gpio_regs __iomem *g = d->regs;
 	unsigned long flags;
 	u32 temp;
@@ -122,10 +119,10 @@
  */
 static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct davinci_gpio_controller *d = chip2controller(chip);
+	struct davinci_gpio_controller *d = gpiochip_get_data(chip);
 	struct davinci_gpio_regs __iomem *g = d->regs;
 
-	return (1 << offset) & readl_relaxed(&g->in_data);
+	return !!((1 << offset) & readl_relaxed(&g->in_data));
 }
 
 /*
@@ -134,7 +131,7 @@
 static void
 davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct davinci_gpio_controller *d = chip2controller(chip);
+	struct davinci_gpio_controller *d = gpiochip_get_data(chip);
 	struct davinci_gpio_regs __iomem *g = d->regs;
 
 	writel_relaxed((1 << offset), value ? &g->set_data : &g->clr_data);
@@ -149,7 +146,7 @@
 	u32 val;
 
 	if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node)
-		return pdev->dev.platform_data;
+		return dev_get_platdata(&pdev->dev);
 
 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
@@ -179,8 +176,8 @@
 			     const struct of_phandle_args *gpiospec,
 			     u32 *flags)
 {
-	struct davinci_gpio_controller *chips = dev_get_drvdata(gc->dev);
-	struct davinci_gpio_platform_data *pdata = dev_get_platdata(gc->dev);
+	struct davinci_gpio_controller *chips = dev_get_drvdata(gc->parent);
+	struct davinci_gpio_platform_data *pdata = dev_get_platdata(gc->parent);
 
 	if (gpiospec->args[0] > pdata->ngpio)
 		return -EINVAL;
@@ -254,7 +251,7 @@
 #ifdef CONFIG_OF_GPIO
 		chips[i].chip.of_gpio_n_cells = 2;
 		chips[i].chip.of_xlate = davinci_gpio_of_xlate;
-		chips[i].chip.dev = dev;
+		chips[i].chip.parent = dev;
 		chips[i].chip.of_node = dev->of_node;
 #endif
 		spin_lock_init(&chips[i].lock);
@@ -265,7 +262,7 @@
 		chips[i].clr_data = &regs->clr_data;
 		chips[i].in_data = &regs->in_data;
 
-		gpiochip_add(&chips[i].chip);
+		gpiochip_add_data(&chips[i].chip, &chips[i]);
 	}
 
 	platform_set_drvdata(pdev, chips);
@@ -368,7 +365,7 @@
 
 static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
 {
-	struct davinci_gpio_controller *d = chip2controller(chip);
+	struct davinci_gpio_controller *d = gpiochip_get_data(chip);
 
 	if (d->irq_domain)
 		return irq_create_mapping(d->irq_domain, d->chip.base + offset);
@@ -378,7 +375,7 @@
 
 static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
 {
-	struct davinci_gpio_controller *d = chip2controller(chip);
+	struct davinci_gpio_controller *d = gpiochip_get_data(chip);
 
 	/*
 	 * NOTE:  we assume for now that only irqs in the first gpio_chip
diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c
index 6685712..e11a7d1 100644
--- a/drivers/gpio/gpio-dln2.c
+++ b/drivers/gpio/gpio-dln2.c
@@ -153,7 +153,7 @@
 
 static int dln2_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
-	struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+	struct dln2_gpio *dln2 = gpiochip_get_data(chip);
 	struct dln2_gpio_pin req = {
 		.pin = cpu_to_le16(offset),
 	};
@@ -194,14 +194,14 @@
 
 static void dln2_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
-	struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+	struct dln2_gpio *dln2 = gpiochip_get_data(chip);
 
 	dln2_gpio_pin_cmd(dln2, DLN2_GPIO_PIN_DISABLE, offset);
 }
 
 static int dln2_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 {
-	struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+	struct dln2_gpio *dln2 = gpiochip_get_data(chip);
 
 	if (test_bit(offset, dln2->output_enabled))
 		return GPIOF_DIR_OUT;
@@ -211,7 +211,7 @@
 
 static int dln2_gpio_get(struct gpio_chip *chip, unsigned int offset)
 {
-	struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+	struct dln2_gpio *dln2 = gpiochip_get_data(chip);
 	int dir;
 
 	dir = dln2_gpio_get_direction(chip, offset);
@@ -226,7 +226,7 @@
 
 static void dln2_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+	struct dln2_gpio *dln2 = gpiochip_get_data(chip);
 
 	dln2_gpio_pin_set_out_val(dln2, offset, value);
 }
@@ -234,7 +234,7 @@
 static int dln2_gpio_set_direction(struct gpio_chip *chip, unsigned offset,
 				   unsigned dir)
 {
-	struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+	struct dln2_gpio *dln2 = gpiochip_get_data(chip);
 	struct dln2_gpio_pin_val req = {
 		.pin = cpu_to_le16(offset),
 		.value = dir,
@@ -262,7 +262,7 @@
 static int dln2_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 				      int value)
 {
-	struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+	struct dln2_gpio *dln2 = gpiochip_get_data(chip);
 	int ret;
 
 	ret = dln2_gpio_pin_set_out_val(dln2, offset, value);
@@ -275,7 +275,7 @@
 static int dln2_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
 				  unsigned debounce)
 {
-	struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+	struct dln2_gpio *dln2 = gpiochip_get_data(chip);
 	__le32 duration = cpu_to_le32(debounce);
 
 	return dln2_transfer_tx(dln2->pdev, DLN2_GPIO_SET_DEBOUNCE,
@@ -302,7 +302,7 @@
 static void dln2_irq_unmask(struct irq_data *irqd)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
-	struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+	struct dln2_gpio *dln2 = gpiochip_get_data(gc);
 	int pin = irqd_to_hwirq(irqd);
 
 	set_bit(pin, dln2->unmasked_irqs);
@@ -311,7 +311,7 @@
 static void dln2_irq_mask(struct irq_data *irqd)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
-	struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+	struct dln2_gpio *dln2 = gpiochip_get_data(gc);
 	int pin = irqd_to_hwirq(irqd);
 
 	clear_bit(pin, dln2->unmasked_irqs);
@@ -320,7 +320,7 @@
 static int dln2_irq_set_type(struct irq_data *irqd, unsigned type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
-	struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+	struct dln2_gpio *dln2 = gpiochip_get_data(gc);
 	int pin = irqd_to_hwirq(irqd);
 
 	switch (type) {
@@ -349,7 +349,7 @@
 static void dln2_irq_bus_lock(struct irq_data *irqd)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
-	struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+	struct dln2_gpio *dln2 = gpiochip_get_data(gc);
 
 	mutex_lock(&dln2->irq_lock);
 }
@@ -357,7 +357,7 @@
 static void dln2_irq_bus_unlock(struct irq_data *irqd)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
-	struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+	struct dln2_gpio *dln2 = gpiochip_get_data(gc);
 	int pin = irqd_to_hwirq(irqd);
 	int enabled, unmasked;
 	unsigned type;
@@ -377,7 +377,7 @@
 
 		ret = dln2_gpio_set_event_cfg(dln2, pin, type, 0);
 		if (ret)
-			dev_err(dln2->gpio.dev, "failed to set event\n");
+			dev_err(dln2->gpio.parent, "failed to set event\n");
 	}
 
 	mutex_unlock(&dln2->irq_lock);
@@ -406,19 +406,19 @@
 	struct dln2_gpio *dln2 = platform_get_drvdata(pdev);
 
 	if (len < sizeof(*event)) {
-		dev_err(dln2->gpio.dev, "short event message\n");
+		dev_err(dln2->gpio.parent, "short event message\n");
 		return;
 	}
 
 	pin = le16_to_cpu(event->pin);
 	if (pin >= dln2->gpio.ngpio) {
-		dev_err(dln2->gpio.dev, "out of bounds pin %d\n", pin);
+		dev_err(dln2->gpio.parent, "out of bounds pin %d\n", pin);
 		return;
 	}
 
 	irq = irq_find_mapping(dln2->gpio.irqdomain, pin);
 	if (!irq) {
-		dev_err(dln2->gpio.dev, "pin %d not mapped to IRQ\n", pin);
+		dev_err(dln2->gpio.parent, "pin %d not mapped to IRQ\n", pin);
 		return;
 	}
 
@@ -462,7 +462,7 @@
 	dln2->pdev = pdev;
 
 	dln2->gpio.label = "dln2";
-	dln2->gpio.dev = dev;
+	dln2->gpio.parent = dev;
 	dln2->gpio.owner = THIS_MODULE;
 	dln2->gpio.base = -1;
 	dln2->gpio.ngpio = pins;
@@ -479,7 +479,7 @@
 
 	platform_set_drvdata(pdev, dln2);
 
-	ret = gpiochip_add(&dln2->gpio);
+	ret = gpiochip_add_data(&dln2->gpio, dln2);
 	if (ret < 0) {
 		dev_err(dev, "failed to add gpio chip: %d\n", ret);
 		goto out;
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index fcd5b0a..597de1e 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -7,7 +7,9 @@
  *
  * All enquiries to support@picochip.com
  */
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
+/* FIXME: for gpio_get_value(), replace this with direct register read */
+#include <linux/gpio.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -66,7 +68,7 @@
 #endif
 
 struct dwapb_gpio_port {
-	struct bgpio_chip	bgc;
+	struct gpio_chip	gc;
 	bool			is_registered;
 	struct dwapb_gpio	*gpio;
 #ifdef CONFIG_PM_SLEEP
@@ -83,33 +85,26 @@
 	struct irq_domain	*domain;
 };
 
-static inline struct dwapb_gpio_port *
-to_dwapb_gpio_port(struct bgpio_chip *bgc)
-{
-	return container_of(bgc, struct dwapb_gpio_port, bgc);
-}
-
 static inline u32 dwapb_read(struct dwapb_gpio *gpio, unsigned int offset)
 {
-	struct bgpio_chip *bgc	= &gpio->ports[0].bgc;
+	struct gpio_chip *gc	= &gpio->ports[0].gc;
 	void __iomem *reg_base	= gpio->regs;
 
-	return bgc->read_reg(reg_base + offset);
+	return gc->read_reg(reg_base + offset);
 }
 
 static inline void dwapb_write(struct dwapb_gpio *gpio, unsigned int offset,
 			       u32 val)
 {
-	struct bgpio_chip *bgc	= &gpio->ports[0].bgc;
+	struct gpio_chip *gc	= &gpio->ports[0].gc;
 	void __iomem *reg_base	= gpio->regs;
 
-	bgc->write_reg(reg_base + offset, val);
+	gc->write_reg(reg_base + offset, val);
 }
 
 static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-	struct dwapb_gpio_port *port = to_dwapb_gpio_port(bgc);
+	struct dwapb_gpio_port *port = gpiochip_get_data(gc);
 	struct dwapb_gpio *gpio = port->gpio;
 
 	return irq_find_mapping(gpio->domain, offset);
@@ -119,7 +114,7 @@
 {
 	u32 v = dwapb_read(gpio, GPIO_INT_POLARITY);
 
-	if (gpio_get_value(gpio->ports[0].bgc.gc.base + offs))
+	if (gpio_get_value(gpio->ports[0].gc.base + offs))
 		v &= ~BIT(offs);
 	else
 		v |= BIT(offs);
@@ -162,39 +157,39 @@
 {
 	struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
 	struct dwapb_gpio *gpio = igc->private;
-	struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+	struct gpio_chip *gc = &gpio->ports[0].gc;
 	unsigned long flags;
 	u32 val;
 
-	spin_lock_irqsave(&bgc->lock, flags);
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
 	val = dwapb_read(gpio, GPIO_INTEN);
 	val |= BIT(d->hwirq);
 	dwapb_write(gpio, GPIO_INTEN, val);
-	spin_unlock_irqrestore(&bgc->lock, flags);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 }
 
 static void dwapb_irq_disable(struct irq_data *d)
 {
 	struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
 	struct dwapb_gpio *gpio = igc->private;
-	struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+	struct gpio_chip *gc = &gpio->ports[0].gc;
 	unsigned long flags;
 	u32 val;
 
-	spin_lock_irqsave(&bgc->lock, flags);
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
 	val = dwapb_read(gpio, GPIO_INTEN);
 	val &= ~BIT(d->hwirq);
 	dwapb_write(gpio, GPIO_INTEN, val);
-	spin_unlock_irqrestore(&bgc->lock, flags);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 }
 
 static int dwapb_irq_reqres(struct irq_data *d)
 {
 	struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
 	struct dwapb_gpio *gpio = igc->private;
-	struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+	struct gpio_chip *gc = &gpio->ports[0].gc;
 
-	if (gpiochip_lock_as_irq(&bgc->gc, irqd_to_hwirq(d))) {
+	if (gpiochip_lock_as_irq(gc, irqd_to_hwirq(d))) {
 		dev_err(gpio->dev, "unable to lock HW IRQ %lu for IRQ\n",
 			irqd_to_hwirq(d));
 		return -EINVAL;
@@ -206,16 +201,16 @@
 {
 	struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
 	struct dwapb_gpio *gpio = igc->private;
-	struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+	struct gpio_chip *gc = &gpio->ports[0].gc;
 
-	gpiochip_unlock_as_irq(&bgc->gc, irqd_to_hwirq(d));
+	gpiochip_unlock_as_irq(gc, irqd_to_hwirq(d));
 }
 
 static int dwapb_irq_set_type(struct irq_data *d, u32 type)
 {
 	struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
 	struct dwapb_gpio *gpio = igc->private;
-	struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+	struct gpio_chip *gc = &gpio->ports[0].gc;
 	int bit = d->hwirq;
 	unsigned long level, polarity, flags;
 
@@ -223,7 +218,7 @@
 		     IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
 		return -EINVAL;
 
-	spin_lock_irqsave(&bgc->lock, flags);
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
 	level = dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
 	polarity = dwapb_read(gpio, GPIO_INT_POLARITY);
 
@@ -254,7 +249,7 @@
 
 	dwapb_write(gpio, GPIO_INTTYPE_LEVEL, level);
 	dwapb_write(gpio, GPIO_INT_POLARITY, polarity);
-	spin_unlock_irqrestore(&bgc->lock, flags);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 
 	return 0;
 }
@@ -262,13 +257,12 @@
 static int dwapb_gpio_set_debounce(struct gpio_chip *gc,
 				   unsigned offset, unsigned debounce)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-	struct dwapb_gpio_port *port = to_dwapb_gpio_port(bgc);
+	struct dwapb_gpio_port *port = gpiochip_get_data(gc);
 	struct dwapb_gpio *gpio = port->gpio;
 	unsigned long flags, val_deb;
-	unsigned long mask = bgc->pin2mask(bgc, offset);
+	unsigned long mask = gc->pin2mask(gc, offset);
 
-	spin_lock_irqsave(&bgc->lock, flags);
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
 
 	val_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
 	if (debounce)
@@ -276,7 +270,7 @@
 	else
 		dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb & ~mask);
 
-	spin_unlock_irqrestore(&bgc->lock, flags);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 
 	return 0;
 }
@@ -295,7 +289,7 @@
 				 struct dwapb_gpio_port *port,
 				 struct dwapb_port_property *pp)
 {
-	struct gpio_chip *gc = &port->bgc.gc;
+	struct gpio_chip *gc = &port->gc;
 	struct device_node *node = pp->node;
 	struct irq_chip_generic	*irq_gc = NULL;
 	unsigned int hwirq, ngpio = gc->ngpio;
@@ -369,13 +363,13 @@
 	for (hwirq = 0 ; hwirq < ngpio ; hwirq++)
 		irq_create_mapping(gpio->domain, hwirq);
 
-	port->bgc.gc.to_irq = dwapb_gpio_to_irq;
+	port->gc.to_irq = dwapb_gpio_to_irq;
 }
 
 static void dwapb_irq_teardown(struct dwapb_gpio *gpio)
 {
 	struct dwapb_gpio_port *port = &gpio->ports[0];
-	struct gpio_chip *gc = &port->bgc.gc;
+	struct gpio_chip *gc = &port->gc;
 	unsigned int ngpio = gc->ngpio;
 	irq_hw_number_t hwirq;
 
@@ -412,7 +406,7 @@
 	dirout = gpio->regs + GPIO_SWPORTA_DDR +
 		(pp->idx * GPIO_SWPORT_DDR_SIZE);
 
-	err = bgpio_init(&port->bgc, gpio->dev, 4, dat, set, NULL, dirout,
+	err = bgpio_init(&port->gc, gpio->dev, 4, dat, set, NULL, dirout,
 			 NULL, false);
 	if (err) {
 		dev_err(gpio->dev, "failed to init gpio chip for %s\n",
@@ -421,19 +415,19 @@
 	}
 
 #ifdef CONFIG_OF_GPIO
-	port->bgc.gc.of_node = pp->node;
+	port->gc.of_node = pp->node;
 #endif
-	port->bgc.gc.ngpio = pp->ngpio;
-	port->bgc.gc.base = pp->gpio_base;
+	port->gc.ngpio = pp->ngpio;
+	port->gc.base = pp->gpio_base;
 
 	/* Only port A support debounce */
 	if (pp->idx == 0)
-		port->bgc.gc.set_debounce = dwapb_gpio_set_debounce;
+		port->gc.set_debounce = dwapb_gpio_set_debounce;
 
 	if (pp->irq)
 		dwapb_configure_irqs(gpio, port, pp);
 
-	err = gpiochip_add(&port->bgc.gc);
+	err = gpiochip_add_data(&port->gc, port);
 	if (err)
 		dev_err(gpio->dev, "failed to register gpiochip for %s\n",
 			pp->name);
@@ -449,7 +443,7 @@
 
 	for (m = 0; m < gpio->nr_ports; ++m)
 		if (gpio->ports[m].is_registered)
-			gpiochip_remove(&gpio->ports[m].bgc.gc);
+			gpiochip_remove(&gpio->ports[m].gc);
 }
 
 static struct dwapb_platform_data *
@@ -591,11 +585,11 @@
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
-	struct bgpio_chip *bgc	= &gpio->ports[0].bgc;
+	struct gpio_chip *gc	= &gpio->ports[0].gc;
 	unsigned long flags;
 	int i;
 
-	spin_lock_irqsave(&bgc->lock, flags);
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
 	for (i = 0; i < gpio->nr_ports; i++) {
 		unsigned int offset;
 		unsigned int idx = gpio->ports[i].idx;
@@ -624,7 +618,7 @@
 			dwapb_write(gpio, GPIO_INTMASK, 0xffffffff);
 		}
 	}
-	spin_unlock_irqrestore(&bgc->lock, flags);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 
 	return 0;
 }
@@ -633,11 +627,11 @@
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
-	struct bgpio_chip *bgc	= &gpio->ports[0].bgc;
+	struct gpio_chip *gc	= &gpio->ports[0].gc;
 	unsigned long flags;
 	int i;
 
-	spin_lock_irqsave(&bgc->lock, flags);
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
 	for (i = 0; i < gpio->nr_ports; i++) {
 		unsigned int offset;
 		unsigned int idx = gpio->ports[i].idx;
@@ -666,7 +660,7 @@
 			dwapb_write(gpio, GPIO_PORTA_EOI, 0xffffffff);
 		}
 	}
-	spin_unlock_irqrestore(&bgc->lock, flags);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 
 	return 0;
 }
diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c
index 6bca1e1..8d32ccc 100644
--- a/drivers/gpio/gpio-em.c
+++ b/drivers/gpio/gpio-em.c
@@ -103,7 +103,7 @@
 	struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
 
 	if (gpiochip_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) {
-		dev_err(p->gpio_chip.dev,
+		dev_err(p->gpio_chip.parent,
 			"unable to lock HW IRQ %lu for IRQ\n",
 			irqd_to_hwirq(d));
 		return -EINVAL;
@@ -192,7 +192,7 @@
 
 static inline struct em_gio_priv *gpio_to_priv(struct gpio_chip *chip)
 {
-	return container_of(chip, struct em_gio_priv, gpio_chip);
+	return gpiochip_get_data(chip);
 }
 
 static int em_gio_direction_input(struct gpio_chip *chip, unsigned offset)
@@ -203,7 +203,7 @@
 
 static int em_gio_get(struct gpio_chip *chip, unsigned offset)
 {
-	return (int)(em_gio_read(gpio_to_priv(chip), GIO_I) & BIT(offset));
+	return !!(em_gio_read(gpio_to_priv(chip), GIO_I) & BIT(offset));
 }
 
 static void __em_gio_set(struct gpio_chip *chip, unsigned int reg,
@@ -332,7 +332,7 @@
 	gpio_chip->request = em_gio_request;
 	gpio_chip->free = em_gio_free;
 	gpio_chip->label = name;
-	gpio_chip->dev = &pdev->dev;
+	gpio_chip->parent = &pdev->dev;
 	gpio_chip->owner = THIS_MODULE;
 	gpio_chip->base = -1;
 	gpio_chip->ngpio = ngpios;
@@ -368,7 +368,7 @@
 		goto err1;
 	}
 
-	ret = gpiochip_add(gpio_chip);
+	ret = gpiochip_add_data(gpio_chip, p);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add GPIO controller\n");
 		goto err1;
diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c
index 3e3947b..ad27907 100644
--- a/drivers/gpio/gpio-ep93xx.c
+++ b/drivers/gpio/gpio-ep93xx.c
@@ -16,10 +16,11 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/gpio.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
+/* FIXME: this is here for gpio_to_irq() - get rid of this! */
+#include <linux/gpio.h>
 
 #include <mach/hardware.h>
 #include <mach/gpio-ep93xx.h>
@@ -28,7 +29,7 @@
 
 struct ep93xx_gpio {
 	void __iomem		*mmio_base;
-	struct bgpio_chip	bgc[8];
+	struct gpio_chip	gc[8];
 };
 
 /*************************************************************************
@@ -319,26 +320,26 @@
 	return 64 + gpio;
 }
 
-static int ep93xx_gpio_add_bank(struct bgpio_chip *bgc, struct device *dev,
+static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
 	void __iomem *mmio_base, struct ep93xx_gpio_bank *bank)
 {
 	void __iomem *data = mmio_base + bank->data;
 	void __iomem *dir =  mmio_base + bank->dir;
 	int err;
 
-	err = bgpio_init(bgc, dev, 1, data, NULL, NULL, dir, NULL, 0);
+	err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0);
 	if (err)
 		return err;
 
-	bgc->gc.label = bank->label;
-	bgc->gc.base = bank->base;
+	gc->label = bank->label;
+	gc->base = bank->base;
 
 	if (bank->has_debounce) {
-		bgc->gc.set_debounce = ep93xx_gpio_set_debounce;
-		bgc->gc.to_irq = ep93xx_gpio_to_irq;
+		gc->set_debounce = ep93xx_gpio_set_debounce;
+		gc->to_irq = ep93xx_gpio_to_irq;
 	}
 
-	return gpiochip_add(&bgc->gc);
+	return gpiochip_add_data(gc, NULL);
 }
 
 static int ep93xx_gpio_probe(struct platform_device *pdev)
@@ -358,10 +359,10 @@
 		return PTR_ERR(ep93xx_gpio->mmio_base);
 
 	for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) {
-		struct bgpio_chip *bgc = &ep93xx_gpio->bgc[i];
+		struct gpio_chip *gc = &ep93xx_gpio->gc[i];
 		struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i];
 
-		if (ep93xx_gpio_add_bank(bgc, &pdev->dev,
+		if (ep93xx_gpio_add_bank(gc, &pdev->dev,
 					 ep93xx_gpio->mmio_base, bank))
 			dev_warn(&pdev->dev, "Unable to add gpio bank %s\n",
 				bank->label);
diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c
index 5c15dd1..00b022c 100644
--- a/drivers/gpio/gpio-etraxfs.c
+++ b/drivers/gpio/gpio-etraxfs.c
@@ -1,12 +1,10 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/gpio.h>
 #include <linux/gpio/driver.h>
 #include <linux/of_gpio.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <linux/basic_mmio_gpio.h>
 
 #define ETRAX_FS_rw_pa_dout	0
 #define ETRAX_FS_r_pa_din	4
@@ -67,7 +65,7 @@
 };
 
 struct etraxfs_gpio_chip {
-	struct bgpio_chip bgc;
+	struct gpio_chip gc;
 	struct etraxfs_gpio_block *block;
 };
 
@@ -176,11 +174,6 @@
 	.rw_intr_pins	= ARTPEC3_rw_intr_pins,
 };
 
-static struct etraxfs_gpio_chip *to_etraxfs(struct gpio_chip *gc)
-{
-	return container_of(gc, struct etraxfs_gpio_chip, bgc.gc);
-}
-
 static unsigned int etraxfs_gpio_chip_to_port(struct gpio_chip *gc)
 {
 	return gc->label[0] - 'A';
@@ -220,13 +213,13 @@
 static unsigned int etraxfs_gpio_to_group_pin(struct etraxfs_gpio_chip *chip,
 					      unsigned int gpio)
 {
-	return 4 * etraxfs_gpio_chip_to_port(&chip->bgc.gc) + gpio / 8;
+	return 4 * etraxfs_gpio_chip_to_port(&chip->gc) + gpio / 8;
 }
 
 static void etraxfs_gpio_irq_ack(struct irq_data *d)
 {
 	struct etraxfs_gpio_chip *chip =
-		to_etraxfs(irq_data_get_irq_chip_data(d));
+		gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	struct etraxfs_gpio_block *block = chip->block;
 	unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
 
@@ -236,7 +229,7 @@
 static void etraxfs_gpio_irq_mask(struct irq_data *d)
 {
 	struct etraxfs_gpio_chip *chip =
-		to_etraxfs(irq_data_get_irq_chip_data(d));
+		gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	struct etraxfs_gpio_block *block = chip->block;
 	unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
 
@@ -249,7 +242,7 @@
 static void etraxfs_gpio_irq_unmask(struct irq_data *d)
 {
 	struct etraxfs_gpio_chip *chip =
-		to_etraxfs(irq_data_get_irq_chip_data(d));
+		gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	struct etraxfs_gpio_block *block = chip->block;
 	unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
 
@@ -262,7 +255,7 @@
 static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type)
 {
 	struct etraxfs_gpio_chip *chip =
-		to_etraxfs(irq_data_get_irq_chip_data(d));
+		gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	struct etraxfs_gpio_block *block = chip->block;
 	unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
 	u32 cfg;
@@ -299,7 +292,7 @@
 static int etraxfs_gpio_irq_request_resources(struct irq_data *d)
 {
 	struct etraxfs_gpio_chip *chip =
-		to_etraxfs(irq_data_get_irq_chip_data(d));
+		gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	struct etraxfs_gpio_block *block = chip->block;
 	unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
 	int ret = -EBUSY;
@@ -308,7 +301,7 @@
 	if (block->group[grpirq])
 		goto out;
 
-	ret = gpiochip_lock_as_irq(&chip->bgc.gc, d->hwirq);
+	ret = gpiochip_lock_as_irq(&chip->gc, d->hwirq);
 	if (ret)
 		goto out;
 
@@ -330,13 +323,13 @@
 static void etraxfs_gpio_irq_release_resources(struct irq_data *d)
 {
 	struct etraxfs_gpio_chip *chip =
-		to_etraxfs(irq_data_get_irq_chip_data(d));
+		gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	struct etraxfs_gpio_block *block = chip->block;
 	unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
 
 	spin_lock(&block->lock);
 	block->group[grpirq] = 0;
-	gpiochip_unlock_as_irq(&chip->bgc.gc, d->hwirq);
+	gpiochip_unlock_as_irq(&chip->gc, d->hwirq);
 	spin_unlock(&block->lock);
 }
 
@@ -419,7 +412,7 @@
 
 	for (i = 0; i < info->num_ports; i++) {
 		struct etraxfs_gpio_chip *chip = &chips[i];
-		struct bgpio_chip *bgc = &chip->bgc;
+		struct gpio_chip *gc = &chip->gc;
 		const struct etraxfs_gpio_port *port = &info->ports[i];
 		unsigned long flags = BGPIOF_READ_OUTPUT_REG_SET;
 		void __iomem *dat = regs + port->din;
@@ -433,7 +426,7 @@
 			flags = BGPIOF_NO_OUTPUT;
 		}
 
-		ret = bgpio_init(bgc, dev, 4,
+		ret = bgpio_init(gc, dev, 4,
 				 dat, set, NULL, dirout, NULL,
 				 flags);
 		if (ret) {
@@ -442,28 +435,28 @@
 			continue;
 		}
 
-		bgc->gc.ngpio = port->ngpio;
-		bgc->gc.label = port->label;
+		gc->ngpio = port->ngpio;
+		gc->label = port->label;
 
-		bgc->gc.of_node = dev->of_node;
-		bgc->gc.of_gpio_n_cells = 3;
-		bgc->gc.of_xlate = etraxfs_gpio_of_xlate;
+		gc->of_node = dev->of_node;
+		gc->of_gpio_n_cells = 3;
+		gc->of_xlate = etraxfs_gpio_of_xlate;
 
-		ret = gpiochip_add(&bgc->gc);
+		ret = gpiochip_add_data(gc, chip);
 		if (ret) {
 			dev_err(dev, "Unable to register port %s\n",
-				bgc->gc.label);
+				gc->label);
 			continue;
 		}
 
 		if (i > 0 && !allportsirq)
 			continue;
 
-		ret = gpiochip_irqchip_add(&bgc->gc, &etraxfs_gpio_irq_chip, 0,
+		ret = gpiochip_irqchip_add(gc, &etraxfs_gpio_irq_chip, 0,
 					   handle_level_irq, IRQ_TYPE_NONE);
 		if (ret) {
 			dev_err(dev, "Unable to add irqchip to port %s\n",
-				bgc->gc.label);
+				gc->label);
 		}
 	}
 
diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
index 5e3c4fa..d62fd6b 100644
--- a/drivers/gpio/gpio-f7188x.c
+++ b/drivers/gpio/gpio-f7188x.c
@@ -193,8 +193,7 @@
 static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
 	int err;
-	struct f7188x_gpio_bank *bank =
-		container_of(chip, struct f7188x_gpio_bank, chip);
+	struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
 	struct f7188x_sio *sio = bank->data->sio;
 	u8 dir;
 
@@ -215,8 +214,7 @@
 static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
 	int err;
-	struct f7188x_gpio_bank *bank =
-		container_of(chip, struct f7188x_gpio_bank, chip);
+	struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
 	struct f7188x_sio *sio = bank->data->sio;
 	u8 dir, data;
 
@@ -241,8 +239,7 @@
 				     unsigned offset, int value)
 {
 	int err;
-	struct f7188x_gpio_bank *bank =
-		container_of(chip, struct f7188x_gpio_bank, chip);
+	struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
 	struct f7188x_sio *sio = bank->data->sio;
 	u8 dir, data_out;
 
@@ -270,8 +267,7 @@
 static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
 	int err;
-	struct f7188x_gpio_bank *bank =
-		container_of(chip, struct f7188x_gpio_bank, chip);
+	struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
 	struct f7188x_sio *sio = bank->data->sio;
 	u8 data_out;
 
@@ -298,7 +294,7 @@
 {
 	int err;
 	int i;
-	struct f7188x_sio *sio = pdev->dev.platform_data;
+	struct f7188x_sio *sio = dev_get_platdata(&pdev->dev);
 	struct f7188x_gpio_data *data;
 
 	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
@@ -333,10 +329,10 @@
 	for (i = 0; i < data->nr_bank; i++) {
 		struct f7188x_gpio_bank *bank = &data->bank[i];
 
-		bank->chip.dev = &pdev->dev;
+		bank->chip.parent = &pdev->dev;
 		bank->data = data;
 
-		err = gpiochip_add(&bank->chip);
+		err = gpiochip_add_data(&bank->chip, bank);
 		if (err) {
 			dev_err(&pdev->dev,
 				"Failed to register gpiochip %d: %d\n",
diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c
index f9ac3f3..cbbec83 100644
--- a/drivers/gpio/gpio-ge.c
+++ b/drivers/gpio/gpio-ge.c
@@ -24,7 +24,7 @@
 #include <linux/of_gpio.h>
 #include <linux/of_address.h>
 #include <linux/module.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
 
 #define GEF_GPIO_DIRECT		0x00
 #define GEF_GPIO_IN		0x04
@@ -55,19 +55,19 @@
 {
 	const struct of_device_id *of_id =
 		of_match_device(gef_gpio_ids, &pdev->dev);
-	struct bgpio_chip *bgc;
+	struct gpio_chip *gc;
 	void __iomem *regs;
 	int ret;
 
-	bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
-	if (!bgc)
+	gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
+	if (!gc)
 		return -ENOMEM;
 
 	regs = of_iomap(pdev->dev.of_node, 0);
 	if (!regs)
 		return -ENOMEM;
 
-	ret = bgpio_init(bgc, &pdev->dev, 4, regs + GEF_GPIO_IN,
+	ret = bgpio_init(gc, &pdev->dev, 4, regs + GEF_GPIO_IN,
 			 regs + GEF_GPIO_OUT, NULL, NULL,
 			 regs + GEF_GPIO_DIRECT, BGPIOF_BIG_ENDIAN_BYTE_ORDER);
 	if (ret) {
@@ -76,20 +76,20 @@
 	}
 
 	/* Setup pointers to chip functions */
-	bgc->gc.label = devm_kstrdup(&pdev->dev, pdev->dev.of_node->full_name,
+	gc->label = devm_kstrdup(&pdev->dev, pdev->dev.of_node->full_name,
 				     GFP_KERNEL);
-	if (!bgc->gc.label) {
+	if (!gc->label) {
 		ret = -ENOMEM;
 		goto err0;
 	}
 
-	bgc->gc.base = -1;
-	bgc->gc.ngpio = (u16)(uintptr_t)of_id->data;
-	bgc->gc.of_gpio_n_cells = 2;
-	bgc->gc.of_node = pdev->dev.of_node;
+	gc->base = -1;
+	gc->ngpio = (u16)(uintptr_t)of_id->data;
+	gc->of_gpio_n_cells = 2;
+	gc->of_node = pdev->dev.of_node;
 
 	/* This function adds a memory mapped GPIO chip */
-	ret = gpiochip_add(&bgc->gc);
+	ret = gpiochip_add_data(gc, NULL);
 	if (ret)
 		goto err0;
 
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index 88ae70d..2a4f233 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -56,11 +56,11 @@
 #include <linux/log2.h>
 #include <linux/ioport.h>
 #include <linux/io.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/slab.h>
+#include <linux/bitops.h>
 #include <linux/platform_device.h>
 #include <linux/mod_devicetable.h>
-#include <linux/basic_mmio_gpio.h>
 
 static void bgpio_write8(void __iomem *reg, unsigned long data)
 {
@@ -124,33 +124,30 @@
 	return ioread32be(reg);
 }
 
-static unsigned long bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin)
+static unsigned long bgpio_pin2mask(struct gpio_chip *gc, unsigned int pin)
 {
-	return 1 << pin;
+	return BIT(pin);
 }
 
-static unsigned long bgpio_pin2mask_be(struct bgpio_chip *bgc,
+static unsigned long bgpio_pin2mask_be(struct gpio_chip *gc,
 				       unsigned int pin)
 {
-	return 1 << (bgc->bits - 1 - pin);
+	return BIT(gc->bgpio_bits - 1 - pin);
 }
 
 static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-	unsigned long pinmask = bgc->pin2mask(bgc, gpio);
+	unsigned long pinmask = gc->pin2mask(gc, gpio);
 
-	if (bgc->dir & pinmask)
-		return !!(bgc->read_reg(bgc->reg_set) & pinmask);
+	if (gc->bgpio_dir & pinmask)
+		return !!(gc->read_reg(gc->reg_set) & pinmask);
 	else
-		return !!(bgc->read_reg(bgc->reg_dat) & pinmask);
+		return !!(gc->read_reg(gc->reg_dat) & pinmask);
 }
 
 static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
-	return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio));
+	return !!(gc->read_reg(gc->reg_dat) & gc->pin2mask(gc, gpio));
 }
 
 static void bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val)
@@ -159,53 +156,50 @@
 
 static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-	unsigned long mask = bgc->pin2mask(bgc, gpio);
+	unsigned long mask = gc->pin2mask(gc, gpio);
 	unsigned long flags;
 
-	spin_lock_irqsave(&bgc->lock, flags);
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
 
 	if (val)
-		bgc->data |= mask;
+		gc->bgpio_data |= mask;
 	else
-		bgc->data &= ~mask;
+		gc->bgpio_data &= ~mask;
 
-	bgc->write_reg(bgc->reg_dat, bgc->data);
+	gc->write_reg(gc->reg_dat, gc->bgpio_data);
 
-	spin_unlock_irqrestore(&bgc->lock, flags);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 }
 
 static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
 				 int val)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-	unsigned long mask = bgc->pin2mask(bgc, gpio);
+	unsigned long mask = gc->pin2mask(gc, gpio);
 
 	if (val)
-		bgc->write_reg(bgc->reg_set, mask);
+		gc->write_reg(gc->reg_set, mask);
 	else
-		bgc->write_reg(bgc->reg_clr, mask);
+		gc->write_reg(gc->reg_clr, mask);
 }
 
 static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-	unsigned long mask = bgc->pin2mask(bgc, gpio);
+	unsigned long mask = gc->pin2mask(gc, gpio);
 	unsigned long flags;
 
-	spin_lock_irqsave(&bgc->lock, flags);
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
 
 	if (val)
-		bgc->data |= mask;
+		gc->bgpio_data |= mask;
 	else
-		bgc->data &= ~mask;
+		gc->bgpio_data &= ~mask;
 
-	bgc->write_reg(bgc->reg_set, bgc->data);
+	gc->write_reg(gc->reg_set, gc->bgpio_data);
 
-	spin_unlock_irqrestore(&bgc->lock, flags);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 }
 
-static void bgpio_multiple_get_masks(struct bgpio_chip *bgc,
+static void bgpio_multiple_get_masks(struct gpio_chip *gc,
 				     unsigned long *mask, unsigned long *bits,
 				     unsigned long *set_mask,
 				     unsigned long *clear_mask)
@@ -215,19 +209,19 @@
 	*set_mask = 0;
 	*clear_mask = 0;
 
-	for (i = 0; i < bgc->bits; i++) {
+	for (i = 0; i < gc->bgpio_bits; i++) {
 		if (*mask == 0)
 			break;
 		if (__test_and_clear_bit(i, mask)) {
 			if (test_bit(i, bits))
-				*set_mask |= bgc->pin2mask(bgc, i);
+				*set_mask |= gc->pin2mask(gc, i);
 			else
-				*clear_mask |= bgc->pin2mask(bgc, i);
+				*clear_mask |= gc->pin2mask(gc, i);
 		}
 	}
 }
 
-static void bgpio_set_multiple_single_reg(struct bgpio_chip *bgc,
+static void bgpio_set_multiple_single_reg(struct gpio_chip *gc,
 					  unsigned long *mask,
 					  unsigned long *bits,
 					  void __iomem *reg)
@@ -235,47 +229,42 @@
 	unsigned long flags;
 	unsigned long set_mask, clear_mask;
 
-	spin_lock_irqsave(&bgc->lock, flags);
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
 
-	bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask);
+	bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
 
-	bgc->data |= set_mask;
-	bgc->data &= ~clear_mask;
+	gc->bgpio_data |= set_mask;
+	gc->bgpio_data &= ~clear_mask;
 
-	bgc->write_reg(reg, bgc->data);
+	gc->write_reg(reg, gc->bgpio_data);
 
-	spin_unlock_irqrestore(&bgc->lock, flags);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 }
 
 static void bgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
 			       unsigned long *bits)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
-	bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_dat);
+	bgpio_set_multiple_single_reg(gc, mask, bits, gc->reg_dat);
 }
 
 static void bgpio_set_multiple_set(struct gpio_chip *gc, unsigned long *mask,
 				   unsigned long *bits)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
-	bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_set);
+	bgpio_set_multiple_single_reg(gc, mask, bits, gc->reg_set);
 }
 
 static void bgpio_set_multiple_with_clear(struct gpio_chip *gc,
 					  unsigned long *mask,
 					  unsigned long *bits)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
 	unsigned long set_mask, clear_mask;
 
-	bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask);
+	bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
 
 	if (set_mask)
-		bgc->write_reg(bgc->reg_set, set_mask);
+		gc->write_reg(gc->reg_set, set_mask);
 	if (clear_mask)
-		bgc->write_reg(bgc->reg_clr, clear_mask);
+		gc->write_reg(gc->reg_clr, clear_mask);
 }
 
 static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
@@ -299,111 +288,103 @@
 
 static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
 	unsigned long flags;
 
-	spin_lock_irqsave(&bgc->lock, flags);
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
 
-	bgc->dir &= ~bgc->pin2mask(bgc, gpio);
-	bgc->write_reg(bgc->reg_dir, bgc->dir);
+	gc->bgpio_dir &= ~gc->pin2mask(gc, gpio);
+	gc->write_reg(gc->reg_dir, gc->bgpio_dir);
 
-	spin_unlock_irqrestore(&bgc->lock, flags);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 
 	return 0;
 }
 
 static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
-	return (bgc->read_reg(bgc->reg_dir) & bgc->pin2mask(bgc, gpio)) ?
-	       GPIOF_DIR_OUT : GPIOF_DIR_IN;
+	/* Return 0 if output, 1 of input */
+	return !(gc->read_reg(gc->reg_dir) & gc->pin2mask(gc, gpio));
 }
 
 static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
 	unsigned long flags;
 
 	gc->set(gc, gpio, val);
 
-	spin_lock_irqsave(&bgc->lock, flags);
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
 
-	bgc->dir |= bgc->pin2mask(bgc, gpio);
-	bgc->write_reg(bgc->reg_dir, bgc->dir);
+	gc->bgpio_dir |= gc->pin2mask(gc, gpio);
+	gc->write_reg(gc->reg_dir, gc->bgpio_dir);
 
-	spin_unlock_irqrestore(&bgc->lock, flags);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 
 	return 0;
 }
 
 static int bgpio_dir_in_inv(struct gpio_chip *gc, unsigned int gpio)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
 	unsigned long flags;
 
-	spin_lock_irqsave(&bgc->lock, flags);
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
 
-	bgc->dir |= bgc->pin2mask(bgc, gpio);
-	bgc->write_reg(bgc->reg_dir, bgc->dir);
+	gc->bgpio_dir |= gc->pin2mask(gc, gpio);
+	gc->write_reg(gc->reg_dir, gc->bgpio_dir);
 
-	spin_unlock_irqrestore(&bgc->lock, flags);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 
 	return 0;
 }
 
 static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
 	unsigned long flags;
 
 	gc->set(gc, gpio, val);
 
-	spin_lock_irqsave(&bgc->lock, flags);
+	spin_lock_irqsave(&gc->bgpio_lock, flags);
 
-	bgc->dir &= ~bgc->pin2mask(bgc, gpio);
-	bgc->write_reg(bgc->reg_dir, bgc->dir);
+	gc->bgpio_dir &= ~gc->pin2mask(gc, gpio);
+	gc->write_reg(gc->reg_dir, gc->bgpio_dir);
 
-	spin_unlock_irqrestore(&bgc->lock, flags);
+	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 
 	return 0;
 }
 
 static int bgpio_get_dir_inv(struct gpio_chip *gc, unsigned int gpio)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
-	return (bgc->read_reg(bgc->reg_dir) & bgc->pin2mask(bgc, gpio)) ?
-	       GPIOF_DIR_IN : GPIOF_DIR_OUT;
+	/* Return 0 if output, 1 if input */
+	return !!(gc->read_reg(gc->reg_dir) & gc->pin2mask(gc, gpio));
 }
 
 static int bgpio_setup_accessors(struct device *dev,
-				 struct bgpio_chip *bgc,
+				 struct gpio_chip *gc,
 				 bool bit_be,
 				 bool byte_be)
 {
 
-	switch (bgc->bits) {
+	switch (gc->bgpio_bits) {
 	case 8:
-		bgc->read_reg	= bgpio_read8;
-		bgc->write_reg	= bgpio_write8;
+		gc->read_reg	= bgpio_read8;
+		gc->write_reg	= bgpio_write8;
 		break;
 	case 16:
 		if (byte_be) {
-			bgc->read_reg	= bgpio_read16be;
-			bgc->write_reg	= bgpio_write16be;
+			gc->read_reg	= bgpio_read16be;
+			gc->write_reg	= bgpio_write16be;
 		} else {
-			bgc->read_reg	= bgpio_read16;
-			bgc->write_reg	= bgpio_write16;
+			gc->read_reg	= bgpio_read16;
+			gc->write_reg	= bgpio_write16;
 		}
 		break;
 	case 32:
 		if (byte_be) {
-			bgc->read_reg	= bgpio_read32be;
-			bgc->write_reg	= bgpio_write32be;
+			gc->read_reg	= bgpio_read32be;
+			gc->write_reg	= bgpio_write32be;
 		} else {
-			bgc->read_reg	= bgpio_read32;
-			bgc->write_reg	= bgpio_write32;
+			gc->read_reg	= bgpio_read32;
+			gc->write_reg	= bgpio_write32;
 		}
 		break;
 #if BITS_PER_LONG >= 64
@@ -413,17 +394,17 @@
 				"64 bit big endian byte order unsupported\n");
 			return -EINVAL;
 		} else {
-			bgc->read_reg	= bgpio_read64;
-			bgc->write_reg	= bgpio_write64;
+			gc->read_reg	= bgpio_read64;
+			gc->write_reg	= bgpio_write64;
 		}
 		break;
 #endif /* BITS_PER_LONG >= 64 */
 	default:
-		dev_err(dev, "unsupported data width %u bits\n", bgc->bits);
+		dev_err(dev, "unsupported data width %u bits\n", gc->bgpio_bits);
 		return -EINVAL;
 	}
 
-	bgc->pin2mask = bit_be ? bgpio_pin2mask_be : bgpio_pin2mask;
+	gc->pin2mask = bit_be ? bgpio_pin2mask_be : bgpio_pin2mask;
 
 	return 0;
 }
@@ -450,44 +431,44 @@
  *	- an input direction register (named "dirin") where a 1 bit indicates
  *	the GPIO is an input.
  */
-static int bgpio_setup_io(struct bgpio_chip *bgc,
+static int bgpio_setup_io(struct gpio_chip *gc,
 			  void __iomem *dat,
 			  void __iomem *set,
 			  void __iomem *clr,
 			  unsigned long flags)
 {
 
-	bgc->reg_dat = dat;
-	if (!bgc->reg_dat)
+	gc->reg_dat = dat;
+	if (!gc->reg_dat)
 		return -EINVAL;
 
 	if (set && clr) {
-		bgc->reg_set = set;
-		bgc->reg_clr = clr;
-		bgc->gc.set = bgpio_set_with_clear;
-		bgc->gc.set_multiple = bgpio_set_multiple_with_clear;
+		gc->reg_set = set;
+		gc->reg_clr = clr;
+		gc->set = bgpio_set_with_clear;
+		gc->set_multiple = bgpio_set_multiple_with_clear;
 	} else if (set && !clr) {
-		bgc->reg_set = set;
-		bgc->gc.set = bgpio_set_set;
-		bgc->gc.set_multiple = bgpio_set_multiple_set;
+		gc->reg_set = set;
+		gc->set = bgpio_set_set;
+		gc->set_multiple = bgpio_set_multiple_set;
 	} else if (flags & BGPIOF_NO_OUTPUT) {
-		bgc->gc.set = bgpio_set_none;
-		bgc->gc.set_multiple = NULL;
+		gc->set = bgpio_set_none;
+		gc->set_multiple = NULL;
 	} else {
-		bgc->gc.set = bgpio_set;
-		bgc->gc.set_multiple = bgpio_set_multiple;
+		gc->set = bgpio_set;
+		gc->set_multiple = bgpio_set_multiple;
 	}
 
 	if (!(flags & BGPIOF_UNREADABLE_REG_SET) &&
 	    (flags & BGPIOF_READ_OUTPUT_REG_SET))
-		bgc->gc.get = bgpio_get_set;
+		gc->get = bgpio_get_set;
 	else
-		bgc->gc.get = bgpio_get;
+		gc->get = bgpio_get;
 
 	return 0;
 }
 
-static int bgpio_setup_direction(struct bgpio_chip *bgc,
+static int bgpio_setup_direction(struct gpio_chip *gc,
 				 void __iomem *dirout,
 				 void __iomem *dirin,
 				 unsigned long flags)
@@ -495,21 +476,21 @@
 	if (dirout && dirin) {
 		return -EINVAL;
 	} else if (dirout) {
-		bgc->reg_dir = dirout;
-		bgc->gc.direction_output = bgpio_dir_out;
-		bgc->gc.direction_input = bgpio_dir_in;
-		bgc->gc.get_direction = bgpio_get_dir;
+		gc->reg_dir = dirout;
+		gc->direction_output = bgpio_dir_out;
+		gc->direction_input = bgpio_dir_in;
+		gc->get_direction = bgpio_get_dir;
 	} else if (dirin) {
-		bgc->reg_dir = dirin;
-		bgc->gc.direction_output = bgpio_dir_out_inv;
-		bgc->gc.direction_input = bgpio_dir_in_inv;
-		bgc->gc.get_direction = bgpio_get_dir_inv;
+		gc->reg_dir = dirin;
+		gc->direction_output = bgpio_dir_out_inv;
+		gc->direction_input = bgpio_dir_in_inv;
+		gc->get_direction = bgpio_get_dir_inv;
 	} else {
 		if (flags & BGPIOF_NO_OUTPUT)
-			bgc->gc.direction_output = bgpio_dir_out_err;
+			gc->direction_output = bgpio_dir_out_err;
 		else
-			bgc->gc.direction_output = bgpio_simple_dir_out;
-		bgc->gc.direction_input = bgpio_simple_dir_in;
+			gc->direction_output = bgpio_simple_dir_out;
+		gc->direction_input = bgpio_simple_dir_in;
 	}
 
 	return 0;
@@ -523,14 +504,7 @@
 	return -EINVAL;
 }
 
-int bgpio_remove(struct bgpio_chip *bgc)
-{
-	gpiochip_remove(&bgc->gc);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(bgpio_remove);
-
-int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
+int bgpio_init(struct gpio_chip *gc, struct device *dev,
 	       unsigned long sz, void __iomem *dat, void __iomem *set,
 	       void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
 	       unsigned long flags)
@@ -540,36 +514,36 @@
 	if (!is_power_of_2(sz))
 		return -EINVAL;
 
-	bgc->bits = sz * 8;
-	if (bgc->bits > BITS_PER_LONG)
+	gc->bgpio_bits = sz * 8;
+	if (gc->bgpio_bits > BITS_PER_LONG)
 		return -EINVAL;
 
-	spin_lock_init(&bgc->lock);
-	bgc->gc.dev = dev;
-	bgc->gc.label = dev_name(dev);
-	bgc->gc.base = -1;
-	bgc->gc.ngpio = bgc->bits;
-	bgc->gc.request = bgpio_request;
+	spin_lock_init(&gc->bgpio_lock);
+	gc->parent = dev;
+	gc->label = dev_name(dev);
+	gc->base = -1;
+	gc->ngpio = gc->bgpio_bits;
+	gc->request = bgpio_request;
 
-	ret = bgpio_setup_io(bgc, dat, set, clr, flags);
+	ret = bgpio_setup_io(gc, dat, set, clr, flags);
 	if (ret)
 		return ret;
 
-	ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN,
+	ret = bgpio_setup_accessors(dev, gc, flags & BGPIOF_BIG_ENDIAN,
 				    flags & BGPIOF_BIG_ENDIAN_BYTE_ORDER);
 	if (ret)
 		return ret;
 
-	ret = bgpio_setup_direction(bgc, dirout, dirin, flags);
+	ret = bgpio_setup_direction(gc, dirout, dirin, flags);
 	if (ret)
 		return ret;
 
-	bgc->data = bgc->read_reg(bgc->reg_dat);
-	if (bgc->gc.set == bgpio_set_set &&
+	gc->bgpio_data = gc->read_reg(gc->reg_dat);
+	if (gc->set == bgpio_set_set &&
 			!(flags & BGPIOF_UNREADABLE_REG_SET))
-		bgc->data = bgc->read_reg(bgc->reg_set);
-	if (bgc->reg_dir && !(flags & BGPIOF_UNREADABLE_REG_DIR))
-		bgc->dir = bgc->read_reg(bgc->reg_dir);
+		gc->bgpio_data = gc->read_reg(gc->reg_set);
+	if (gc->reg_dir && !(flags & BGPIOF_UNREADABLE_REG_DIR))
+		gc->bgpio_dir = gc->read_reg(gc->reg_dir);
 
 	return ret;
 }
@@ -607,7 +581,7 @@
 	unsigned long sz;
 	unsigned long flags = pdev->id_entry->driver_data;
 	int err;
-	struct bgpio_chip *bgc;
+	struct gpio_chip *gc;
 	struct bgpio_pdata *pdata = dev_get_platdata(dev);
 
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
@@ -636,32 +610,33 @@
 	if (IS_ERR(dirin))
 		return PTR_ERR(dirin);
 
-	bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
-	if (!bgc)
+	gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
+	if (!gc)
 		return -ENOMEM;
 
-	err = bgpio_init(bgc, dev, sz, dat, set, clr, dirout, dirin, flags);
+	err = bgpio_init(gc, dev, sz, dat, set, clr, dirout, dirin, flags);
 	if (err)
 		return err;
 
 	if (pdata) {
 		if (pdata->label)
-			bgc->gc.label = pdata->label;
-		bgc->gc.base = pdata->base;
+			gc->label = pdata->label;
+		gc->base = pdata->base;
 		if (pdata->ngpio > 0)
-			bgc->gc.ngpio = pdata->ngpio;
+			gc->ngpio = pdata->ngpio;
 	}
 
-	platform_set_drvdata(pdev, bgc);
+	platform_set_drvdata(pdev, gc);
 
-	return gpiochip_add(&bgc->gc);
+	return gpiochip_add_data(gc, NULL);
 }
 
 static int bgpio_pdev_remove(struct platform_device *pdev)
 {
-	struct bgpio_chip *bgc = platform_get_drvdata(pdev);
+	struct gpio_chip *gc = platform_get_drvdata(pdev);
 
-	return bgpio_remove(bgc);
+	gpiochip_remove(gc);
+	return 0;
 }
 
 static const struct platform_device_id bgpio_id_table[] = {
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
index 801423f..7847dd3 100644
--- a/drivers/gpio/gpio-grgpio.c
+++ b/drivers/gpio/gpio-grgpio.c
@@ -31,7 +31,7 @@
 #include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/err.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
@@ -63,7 +63,7 @@
 };
 
 struct grgpio_priv {
-	struct bgpio_chip bgc;
+	struct gpio_chip gc;
 	void __iomem *regs;
 	struct device *dev;
 
@@ -92,29 +92,22 @@
 	struct grgpio_lirq lirqs[GRGPIO_MAX_NGPIO];
 };
 
-static inline struct grgpio_priv *grgpio_gc_to_priv(struct gpio_chip *gc)
-{
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
-	return container_of(bgc, struct grgpio_priv, bgc);
-}
-
 static void grgpio_set_imask(struct grgpio_priv *priv, unsigned int offset,
 			     int val)
 {
-	struct bgpio_chip *bgc = &priv->bgc;
-	unsigned long mask = bgc->pin2mask(bgc, offset);
+	struct gpio_chip *gc = &priv->gc;
+	unsigned long mask = gc->pin2mask(gc, offset);
 
 	if (val)
 		priv->imask |= mask;
 	else
 		priv->imask &= ~mask;
-	bgc->write_reg(priv->regs + GRGPIO_IMASK, priv->imask);
+	gc->write_reg(priv->regs + GRGPIO_IMASK, priv->imask);
 }
 
 static int grgpio_to_irq(struct gpio_chip *gc, unsigned offset)
 {
-	struct grgpio_priv *priv = grgpio_gc_to_priv(gc);
+	struct grgpio_priv *priv = gpiochip_get_data(gc);
 
 	if (offset >= gc->ngpio)
 		return -ENXIO;
@@ -158,15 +151,15 @@
 		return -EINVAL;
 	}
 
-	spin_lock_irqsave(&priv->bgc.lock, flags);
+	spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
 
-	ipol = priv->bgc.read_reg(priv->regs + GRGPIO_IPOL) & ~mask;
-	iedge = priv->bgc.read_reg(priv->regs + GRGPIO_IEDGE) & ~mask;
+	ipol = priv->gc.read_reg(priv->regs + GRGPIO_IPOL) & ~mask;
+	iedge = priv->gc.read_reg(priv->regs + GRGPIO_IEDGE) & ~mask;
 
-	priv->bgc.write_reg(priv->regs + GRGPIO_IPOL, ipol | pol);
-	priv->bgc.write_reg(priv->regs + GRGPIO_IEDGE, iedge | edge);
+	priv->gc.write_reg(priv->regs + GRGPIO_IPOL, ipol | pol);
+	priv->gc.write_reg(priv->regs + GRGPIO_IEDGE, iedge | edge);
 
-	spin_unlock_irqrestore(&priv->bgc.lock, flags);
+	spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
 
 	return 0;
 }
@@ -177,11 +170,11 @@
 	int offset = d->hwirq;
 	unsigned long flags;
 
-	spin_lock_irqsave(&priv->bgc.lock, flags);
+	spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
 
 	grgpio_set_imask(priv, offset, 0);
 
-	spin_unlock_irqrestore(&priv->bgc.lock, flags);
+	spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
 }
 
 static void grgpio_irq_unmask(struct irq_data *d)
@@ -190,11 +183,11 @@
 	int offset = d->hwirq;
 	unsigned long flags;
 
-	spin_lock_irqsave(&priv->bgc.lock, flags);
+	spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
 
 	grgpio_set_imask(priv, offset, 1);
 
-	spin_unlock_irqrestore(&priv->bgc.lock, flags);
+	spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
 }
 
 static struct irq_chip grgpio_irq_chip = {
@@ -207,12 +200,12 @@
 static irqreturn_t grgpio_irq_handler(int irq, void *dev)
 {
 	struct grgpio_priv *priv = dev;
-	int ngpio = priv->bgc.gc.ngpio;
+	int ngpio = priv->gc.ngpio;
 	unsigned long flags;
 	int i;
 	int match = 0;
 
-	spin_lock_irqsave(&priv->bgc.lock, flags);
+	spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
 
 	/*
 	 * For each gpio line, call its interrupt handler if it its underlying
@@ -228,7 +221,7 @@
 		}
 	}
 
-	spin_unlock_irqrestore(&priv->bgc.lock, flags);
+	spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
 
 	if (!match)
 		dev_warn(priv->dev, "No gpio line matched irq %d\n", irq);
@@ -260,7 +253,7 @@
 	dev_dbg(priv->dev, "Mapping irq %d for gpio line %d\n",
 		irq, offset);
 
-	spin_lock_irqsave(&priv->bgc.lock, flags);
+	spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
 
 	/* Request underlying irq if not already requested */
 	lirq->irq = irq;
@@ -273,14 +266,14 @@
 				"Could not request underlying irq %d\n",
 				uirq->uirq);
 
-			spin_unlock_irqrestore(&priv->bgc.lock, flags);
+			spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
 
 			return ret;
 		}
 	}
 	uirq->refcnt++;
 
-	spin_unlock_irqrestore(&priv->bgc.lock, flags);
+	spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
 
 	/* Setup irq  */
 	irq_set_chip_data(irq, priv);
@@ -298,13 +291,13 @@
 	struct grgpio_lirq *lirq;
 	struct grgpio_uirq *uirq;
 	unsigned long flags;
-	int ngpio = priv->bgc.gc.ngpio;
+	int ngpio = priv->gc.ngpio;
 	int i;
 
 	irq_set_chip_and_handler(irq, NULL, NULL);
 	irq_set_chip_data(irq, NULL);
 
-	spin_lock_irqsave(&priv->bgc.lock, flags);
+	spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
 
 	/* Free underlying irq if last user unmapped */
 	index = -1;
@@ -326,7 +319,7 @@
 			free_irq(uirq->uirq, priv);
 	}
 
-	spin_unlock_irqrestore(&priv->bgc.lock, flags);
+	spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
 }
 
 static const struct irq_domain_ops grgpio_irq_domain_ops = {
@@ -341,7 +334,6 @@
 	struct device_node *np = ofdev->dev.of_node;
 	void  __iomem *regs;
 	struct gpio_chip *gc;
-	struct bgpio_chip *bgc;
 	struct grgpio_priv *priv;
 	struct resource *res;
 	int err;
@@ -359,8 +351,8 @@
 	if (IS_ERR(regs))
 		return PTR_ERR(regs);
 
-	bgc = &priv->bgc;
-	err = bgpio_init(bgc, &ofdev->dev, 4, regs + GRGPIO_DATA,
+	gc = &priv->gc;
+	err = bgpio_init(gc, &ofdev->dev, 4, regs + GRGPIO_DATA,
 			 regs + GRGPIO_OUTPUT, NULL, regs + GRGPIO_DIR, NULL,
 			 BGPIOF_BIG_ENDIAN_BYTE_ORDER);
 	if (err) {
@@ -369,10 +361,9 @@
 	}
 
 	priv->regs = regs;
-	priv->imask = bgc->read_reg(regs + GRGPIO_IMASK);
+	priv->imask = gc->read_reg(regs + GRGPIO_IMASK);
 	priv->dev = &ofdev->dev;
 
-	gc = &bgc->gc;
 	gc->of_node = np;
 	gc->owner = THIS_MODULE;
 	gc->to_irq = grgpio_to_irq;
@@ -435,7 +426,7 @@
 
 	platform_set_drvdata(ofdev, priv);
 
-	err = gpiochip_add(gc);
+	err = gpiochip_add_data(gc, priv);
 	if (err) {
 		dev_err(&ofdev->dev, "Could not add gpiochip\n");
 		if (priv->domain)
@@ -456,7 +447,7 @@
 	int i;
 	int ret = 0;
 
-	spin_lock_irqsave(&priv->bgc.lock, flags);
+	spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
 
 	if (priv->domain) {
 		for (i = 0; i < GRGPIO_MAX_NGPIO; i++) {
@@ -467,13 +458,13 @@
 		}
 	}
 
-	gpiochip_remove(&priv->bgc.gc);
+	gpiochip_remove(&priv->gc);
 
 	if (priv->domain)
 		irq_domain_remove(priv->domain);
 
 out:
-	spin_unlock_irqrestore(&priv->bgc.lock, flags);
+	spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
 
 	return ret;
 }
diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c
index 4ba7ed5..a489338 100644
--- a/drivers/gpio/gpio-ich.c
+++ b/drivers/gpio/gpio-ich.c
@@ -282,7 +282,7 @@
 {
 	chip->owner = THIS_MODULE;
 	chip->label = DRV_NAME;
-	chip->dev = &ichx_priv.dev->dev;
+	chip->parent = &ichx_priv.dev->dev;
 
 	/* Allow chip-specific overrides of request()/get() */
 	chip->request = ichx_priv.desc->request ?
@@ -499,7 +499,7 @@
 
 init:
 	ichx_gpiolib_setup(&ichx_priv.chip);
-	err = gpiochip_add(&ichx_priv.chip);
+	err = gpiochip_add_data(&ichx_priv.chip, NULL);
 	if (err) {
 		pr_err("Failed to register GPIOs\n");
 		goto add_err;
diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c
index 7009747..cdaba13 100644
--- a/drivers/gpio/gpio-intel-mid.c
+++ b/drivers/gpio/gpio-intel-mid.c
@@ -78,15 +78,10 @@
 	struct pci_dev			*pdev;
 };
 
-static inline struct intel_mid_gpio *to_intel_gpio_priv(struct gpio_chip *gc)
-{
-	return container_of(gc, struct intel_mid_gpio, chip);
-}
-
 static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
 			      enum GPIO_REG reg_type)
 {
-	struct intel_mid_gpio *priv = to_intel_gpio_priv(chip);
+	struct intel_mid_gpio *priv = gpiochip_get_data(chip);
 	unsigned nreg = chip->ngpio / 32;
 	u8 reg = offset / 32;
 
@@ -96,7 +91,7 @@
 static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
 				   enum GPIO_REG reg_type)
 {
-	struct intel_mid_gpio *priv = to_intel_gpio_priv(chip);
+	struct intel_mid_gpio *priv = gpiochip_get_data(chip);
 	unsigned nreg = chip->ngpio / 32;
 	u8 reg = offset / 16;
 
@@ -120,7 +115,7 @@
 {
 	void __iomem *gplr = gpio_reg(chip, offset, GPLR);
 
-	return readl(gplr) & BIT(offset % 32);
+	return !!(readl(gplr) & BIT(offset % 32));
 }
 
 static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -138,7 +133,7 @@
 
 static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct intel_mid_gpio *priv = to_intel_gpio_priv(chip);
+	struct intel_mid_gpio *priv = gpiochip_get_data(chip);
 	void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
 	u32 value;
 	unsigned long flags;
@@ -161,7 +156,7 @@
 static int intel_gpio_direction_output(struct gpio_chip *chip,
 			unsigned offset, int value)
 {
-	struct intel_mid_gpio *priv = to_intel_gpio_priv(chip);
+	struct intel_mid_gpio *priv = gpiochip_get_data(chip);
 	void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
 	unsigned long flags;
 
@@ -185,7 +180,7 @@
 static int intel_mid_irq_type(struct irq_data *d, unsigned type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct intel_mid_gpio *priv = to_intel_gpio_priv(gc);
+	struct intel_mid_gpio *priv = gpiochip_get_data(gc);
 	u32 gpio = irqd_to_hwirq(d);
 	unsigned long flags;
 	u32 value;
@@ -304,7 +299,7 @@
 static void intel_mid_irq_handler(struct irq_desc *desc)
 {
 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
-	struct intel_mid_gpio *priv = to_intel_gpio_priv(gc);
+	struct intel_mid_gpio *priv = gpiochip_get_data(gc);
 	struct irq_data *data = irq_desc_get_irq_data(desc);
 	struct irq_chip *chip = irq_data_get_irq_chip(data);
 	u32 base, gpio, mask;
@@ -392,7 +387,7 @@
 
 	priv->reg_base = pcim_iomap_table(pdev)[0];
 	priv->chip.label = dev_name(&pdev->dev);
-	priv->chip.dev = &pdev->dev;
+	priv->chip.parent = &pdev->dev;
 	priv->chip.request = intel_gpio_request;
 	priv->chip.direction_input = intel_gpio_direction_input;
 	priv->chip.direction_output = intel_gpio_direction_output;
@@ -406,7 +401,7 @@
 	spin_lock_init(&priv->lock);
 
 	pci_set_drvdata(pdev, priv);
-	retval = gpiochip_add(&priv->chip);
+	retval = gpiochip_add_data(&priv->chip, priv);
 	if (retval) {
 		dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);
 		return retval;
diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c
index 2ed0237..fb65e58 100644
--- a/drivers/gpio/gpio-iop.c
+++ b/drivers/gpio/gpio-iop.c
@@ -114,7 +114,7 @@
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
-	return gpiochip_add(&iop3xx_chip);
+	return gpiochip_add_data(&iop3xx_chip, NULL);
 }
 
 static struct platform_driver iop3xx_gpio_driver = {
diff --git a/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c
index 21f6f7c..b219c82 100644
--- a/drivers/gpio/gpio-it87.c
+++ b/drivers/gpio/gpio-it87.c
@@ -77,11 +77,6 @@
 	.lock = __SPIN_LOCK_UNLOCKED(it87_gpio_chip.lock),
 };
 
-static inline struct it87_gpio *to_it87_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct it87_gpio, chip);
-}
-
 /* Superio chip access functions; copied from wdt_it87 */
 
 static inline int superio_enter(void)
@@ -165,7 +160,7 @@
 {
 	u8 mask, group;
 	int rc = 0;
-	struct it87_gpio *it87_gpio = to_it87_gpio(chip);
+	struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
 
 	mask = 1 << (gpio_num % 8);
 	group = (gpio_num / 8);
@@ -198,7 +193,7 @@
 {
 	u16 reg;
 	u8 mask;
-	struct it87_gpio *it87_gpio = to_it87_gpio(chip);
+	struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
 
 	mask = 1 << (gpio_num % 8);
 	reg = (gpio_num / 8) + it87_gpio->io_base;
@@ -210,7 +205,7 @@
 {
 	u8 mask, group;
 	int rc = 0;
-	struct it87_gpio *it87_gpio = to_it87_gpio(chip);
+	struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
 
 	mask = 1 << (gpio_num % 8);
 	group = (gpio_num / 8);
@@ -236,7 +231,7 @@
 {
 	u8 mask, curr_vals;
 	u16 reg;
-	struct it87_gpio *it87_gpio = to_it87_gpio(chip);
+	struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
 
 	mask = 1 << (gpio_num % 8);
 	reg = (gpio_num / 8) + it87_gpio->io_base;
@@ -253,7 +248,7 @@
 {
 	u8 mask, group;
 	int rc = 0;
-	struct it87_gpio *it87_gpio = to_it87_gpio(chip);
+	struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
 
 	mask = 1 << (gpio_num % 8);
 	group = (gpio_num / 8);
@@ -380,7 +375,7 @@
 
 	it87_gpio->chip.names = (const char *const*)labels_table;
 
-	rc = gpiochip_add(&it87_gpio->chip);
+	rc = gpiochip_add_data(&it87_gpio->chip, it87_gpio);
 	if (rc)
 		goto labels_free;
 
diff --git a/drivers/gpio/gpio-janz-ttl.c b/drivers/gpio/gpio-janz-ttl.c
index 3a16643..482aa03 100644
--- a/drivers/gpio/gpio-janz-ttl.c
+++ b/drivers/gpio/gpio-janz-ttl.c
@@ -59,7 +59,7 @@
 
 static int ttl_get_value(struct gpio_chip *gpio, unsigned offset)
 {
-	struct ttl_module *mod = dev_get_drvdata(gpio->dev);
+	struct ttl_module *mod = dev_get_drvdata(gpio->parent);
 	u8 *shadow;
 	int ret;
 
@@ -76,12 +76,12 @@
 	spin_lock(&mod->lock);
 	ret = *shadow & (1 << offset);
 	spin_unlock(&mod->lock);
-	return ret;
+	return !!ret;
 }
 
 static void ttl_set_value(struct gpio_chip *gpio, unsigned offset, int value)
 {
-	struct ttl_module *mod = dev_get_drvdata(gpio->dev);
+	struct ttl_module *mod = dev_get_drvdata(gpio->parent);
 	void __iomem *port;
 	u8 *shadow;
 
@@ -172,7 +172,7 @@
 
 	/* Initialize the GPIO data structures */
 	gpio = &mod->gpio;
-	gpio->dev = &pdev->dev;
+	gpio->parent = &pdev->dev;
 	gpio->label = pdev->name;
 	gpio->get = ttl_get_value;
 	gpio->set = ttl_set_value;
@@ -182,7 +182,7 @@
 	gpio->base = -1;
 	gpio->ngpio = 20;
 
-	ret = gpiochip_add(gpio);
+	ret = gpiochip_add_data(gpio, NULL);
 	if (ret) {
 		dev_err(dev, "unable to add GPIO chip\n");
 		return ret;
diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c
index 83f281d..0111774 100644
--- a/drivers/gpio/gpio-kempld.c
+++ b/drivers/gpio/gpio-kempld.c
@@ -65,17 +65,15 @@
 
 static int kempld_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct kempld_gpio_data *gpio
-		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_gpio_data *gpio = gpiochip_get_data(chip);
 	struct kempld_device_data *pld = gpio->pld;
 
-	return kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL_NUM(offset), offset);
+	return !!kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL_NUM(offset), offset);
 }
 
 static void kempld_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct kempld_gpio_data *gpio
-		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_gpio_data *gpio = gpiochip_get_data(chip);
 	struct kempld_device_data *pld = gpio->pld;
 
 	kempld_get_mutex(pld);
@@ -85,8 +83,7 @@
 
 static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct kempld_gpio_data *gpio
-		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_gpio_data *gpio = gpiochip_get_data(chip);
 	struct kempld_device_data *pld = gpio->pld;
 
 	kempld_get_mutex(pld);
@@ -99,8 +96,7 @@
 static int kempld_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 					int value)
 {
-	struct kempld_gpio_data *gpio
-		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_gpio_data *gpio = gpiochip_get_data(chip);
 	struct kempld_device_data *pld = gpio->pld;
 
 	kempld_get_mutex(pld);
@@ -113,8 +109,7 @@
 
 static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 {
-	struct kempld_gpio_data *gpio
-		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_gpio_data *gpio = gpiochip_get_data(chip);
 	struct kempld_device_data *pld = gpio->pld;
 
 	return !kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset);
@@ -166,7 +161,7 @@
 	chip = &gpio->chip;
 	chip->label = "gpio-kempld";
 	chip->owner = THIS_MODULE;
-	chip->dev = dev;
+	chip->parent = dev;
 	chip->can_sleep = true;
 	if (pdata && pdata->gpio_base)
 		chip->base = pdata->gpio_base;
@@ -183,7 +178,7 @@
 		return -ENODEV;
 	}
 
-	ret = gpiochip_add(chip);
+	ret = gpiochip_add_data(chip, gpio);
 	if (ret) {
 		dev_err(dev, "Could not register GPIO chip\n");
 		return ret;
diff --git a/drivers/gpio/gpio-ks8695.c b/drivers/gpio/gpio-ks8695.c
index cc09b23..9f86ed9 100644
--- a/drivers/gpio/gpio-ks8695.c
+++ b/drivers/gpio/gpio-ks8695.c
@@ -234,7 +234,7 @@
 /* Register the GPIOs */
 void ks8695_register_gpios(void)
 {
-	if (gpiochip_add(&ks8695_gpio_chip))
+	if (gpiochip_add_data(&ks8695_gpio_chip, NULL))
 		printk(KERN_ERR "Unable to register core GPIOs\n");
 }
 
diff --git a/drivers/gpio/gpio-loongson.c b/drivers/gpio/gpio-loongson.c
index ccc65a1..92c4fe7 100644
--- a/drivers/gpio/gpio-loongson.c
+++ b/drivers/gpio/gpio-loongson.c
@@ -110,6 +110,6 @@
 
 static int __init loongson_gpio_setup(void)
 {
-	return gpiochip_add(&loongson_chip);
+	return gpiochip_add_data(&loongson_chip, NULL);
 }
 postcore_initcall(loongson_gpio_setup);
diff --git a/drivers/gpio/gpio-lp3943.c b/drivers/gpio/gpio-lp3943.c
index cfc5b12..1c8e2ae 100644
--- a/drivers/gpio/gpio-lp3943.c
+++ b/drivers/gpio/gpio-lp3943.c
@@ -45,14 +45,9 @@
 	u16 input_mask;		/* 1 = GPIO is input direction, 0 = output */
 };
 
-static inline struct lp3943_gpio *to_lp3943_gpio(struct gpio_chip *_chip)
-{
-	return container_of(_chip, struct lp3943_gpio, chip);
-}
-
 static int lp3943_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
-	struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+	struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
 	struct lp3943 *lp3943 = lp3943_gpio->lp3943;
 
 	/* Return an error if the pin is already assigned */
@@ -64,7 +59,7 @@
 
 static void lp3943_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
-	struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+	struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
 	struct lp3943 *lp3943 = lp3943_gpio->lp3943;
 
 	clear_bit(offset, &lp3943->pin_used);
@@ -82,7 +77,7 @@
 
 static int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+	struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
 
 	lp3943_gpio->input_mask |= BIT(offset);
 
@@ -138,7 +133,7 @@
 
 static int lp3943_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+	struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
 
 	/*
 	 * Limitation:
@@ -157,7 +152,7 @@
 
 static void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+	struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
 	u8 data;
 
 	if (value)
@@ -171,7 +166,7 @@
 static int lp3943_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 					int value)
 {
-	struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+	struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
 
 	lp3943_gpio_set(chip, offset, value);
 	lp3943_gpio->input_mask &= ~BIT(offset);
@@ -205,11 +200,11 @@
 
 	lp3943_gpio->lp3943 = lp3943;
 	lp3943_gpio->chip = lp3943_gpio_chip;
-	lp3943_gpio->chip.dev = &pdev->dev;
+	lp3943_gpio->chip.parent = &pdev->dev;
 
 	platform_set_drvdata(pdev, lp3943_gpio);
 
-	return gpiochip_add(&lp3943_gpio->chip);
+	return gpiochip_add_data(&lp3943_gpio->chip, lp3943_gpio);
 }
 
 static int lp3943_gpio_remove(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-lpc18xx.c b/drivers/gpio/gpio-lpc18xx.c
index e39dcb0..98832c9 100644
--- a/drivers/gpio/gpio-lpc18xx.c
+++ b/drivers/gpio/gpio-lpc18xx.c
@@ -31,27 +31,22 @@
 	spinlock_t lock;
 };
 
-static inline struct lpc18xx_gpio_chip *to_lpc18xx_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct lpc18xx_gpio_chip, gpio);
-}
-
 static void lpc18xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip);
+	struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
 	writeb(value ? 1 : 0, gc->base + offset);
 }
 
 static int lpc18xx_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip);
+	struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
 	return !!readb(gc->base + offset);
 }
 
 static int lpc18xx_gpio_direction(struct gpio_chip *chip, unsigned offset,
 				  bool out)
 {
-	struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip);
+	struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
 	unsigned long flags;
 	u32 port, pin, dir;
 
@@ -127,9 +122,9 @@
 
 	spin_lock_init(&gc->lock);
 
-	gc->gpio.dev = &pdev->dev;
+	gc->gpio.parent = &pdev->dev;
 
-	ret = gpiochip_add(&gc->gpio);
+	ret = gpiochip_add_data(&gc->gpio, gc);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add gpio chip\n");
 		clk_disable_unprepare(gc->clk);
diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c
index 47e2dde..4cecf4c 100644
--- a/drivers/gpio/gpio-lpc32xx.c
+++ b/drivers/gpio/gpio-lpc32xx.c
@@ -165,12 +165,6 @@
 	struct gpio_regs	*gpio_grp;
 };
 
-static inline struct lpc32xx_gpio_chip *to_lpc32xx_gpio(
-	struct gpio_chip *gpc)
-{
-	return container_of(gpc, struct lpc32xx_gpio_chip, chip);
-}
-
 static void __set_gpio_dir_p012(struct lpc32xx_gpio_chip *group,
 	unsigned pin, int input)
 {
@@ -261,7 +255,7 @@
 static int lpc32xx_gpio_dir_input_p012(struct gpio_chip *chip,
 	unsigned pin)
 {
-	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+	struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
 
 	__set_gpio_dir_p012(group, pin, 1);
 
@@ -271,7 +265,7 @@
 static int lpc32xx_gpio_dir_input_p3(struct gpio_chip *chip,
 	unsigned pin)
 {
-	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+	struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
 
 	__set_gpio_dir_p3(group, pin, 1);
 
@@ -286,29 +280,29 @@
 
 static int lpc32xx_gpio_get_value_p012(struct gpio_chip *chip, unsigned pin)
 {
-	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+	struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
 
-	return __get_gpio_state_p012(group, pin);
+	return !!__get_gpio_state_p012(group, pin);
 }
 
 static int lpc32xx_gpio_get_value_p3(struct gpio_chip *chip, unsigned pin)
 {
-	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+	struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
 
-	return __get_gpio_state_p3(group, pin);
+	return !!__get_gpio_state_p3(group, pin);
 }
 
 static int lpc32xx_gpi_get_value(struct gpio_chip *chip, unsigned pin)
 {
-	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+	struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
 
-	return __get_gpi_state_p3(group, pin);
+	return !!__get_gpi_state_p3(group, pin);
 }
 
 static int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin,
 	int value)
 {
-	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+	struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
 
 	__set_gpio_level_p012(group, pin, value);
 	__set_gpio_dir_p012(group, pin, 0);
@@ -319,7 +313,7 @@
 static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin,
 	int value)
 {
-	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+	struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
 
 	__set_gpio_level_p3(group, pin, value);
 	__set_gpio_dir_p3(group, pin, 0);
@@ -330,7 +324,7 @@
 static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin,
 	int value)
 {
-	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+	struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
 
 	__set_gpo_level_p3(group, pin, value);
 	return 0;
@@ -339,7 +333,7 @@
 static void lpc32xx_gpio_set_value_p012(struct gpio_chip *chip, unsigned pin,
 	int value)
 {
-	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+	struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
 
 	__set_gpio_level_p012(group, pin, value);
 }
@@ -347,7 +341,7 @@
 static void lpc32xx_gpio_set_value_p3(struct gpio_chip *chip, unsigned pin,
 	int value)
 {
-	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+	struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
 
 	__set_gpio_level_p3(group, pin, value);
 }
@@ -355,16 +349,16 @@
 static void lpc32xx_gpo_set_value(struct gpio_chip *chip, unsigned pin,
 	int value)
 {
-	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+	struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
 
 	__set_gpo_level_p3(group, pin, value);
 }
 
 static int lpc32xx_gpo_get_value(struct gpio_chip *chip, unsigned pin)
 {
-	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+	struct lpc32xx_gpio_chip *group = gpiochip_get_data(chip);
 
-	return __get_gpo_state_p3(group, pin);
+	return !!__get_gpo_state_p3(group, pin);
 }
 
 static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin)
@@ -553,7 +547,8 @@
 			lpc32xx_gpiochip[i].chip.of_gpio_n_cells = 3;
 			lpc32xx_gpiochip[i].chip.of_node = pdev->dev.of_node;
 		}
-		gpiochip_add(&lpc32xx_gpiochip[i].chip);
+		gpiochip_add_data(&lpc32xx_gpiochip[i].chip,
+				  &lpc32xx_gpiochip[i]);
 	}
 
 	return 0;
diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c
index 127c37b..1310777 100644
--- a/drivers/gpio/gpio-lynxpoint.c
+++ b/drivers/gpio/gpio-lynxpoint.c
@@ -97,7 +97,7 @@
 static unsigned long lp_gpio_reg(struct gpio_chip *chip, unsigned offset,
 				 int reg)
 {
-	struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+	struct lp_gpio *lg = gpiochip_get_data(chip);
 	int reg_offset;
 
 	if (reg == LP_CONFIG1 || reg == LP_CONFIG2)
@@ -112,7 +112,7 @@
 
 static int lp_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
-	struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+	struct lp_gpio *lg = gpiochip_get_data(chip);
 	unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
 	unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2);
 	unsigned long acpi_use = lp_gpio_reg(chip, offset, LP_ACPI_OWNED);
@@ -137,7 +137,7 @@
 
 static void lp_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
-	struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+	struct lp_gpio *lg = gpiochip_get_data(chip);
 	unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2);
 
 	/* disable input sensing */
@@ -149,7 +149,7 @@
 static int lp_irq_type(struct irq_data *d, unsigned type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
+	struct lp_gpio *lg = gpiochip_get_data(gc);
 	u32 hwirq = irqd_to_hwirq(d);
 	unsigned long flags;
 	u32 value;
@@ -191,7 +191,7 @@
 
 static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+	struct lp_gpio *lg = gpiochip_get_data(chip);
 	unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
 	unsigned long flags;
 
@@ -207,7 +207,7 @@
 
 static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+	struct lp_gpio *lg = gpiochip_get_data(chip);
 	unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
 	unsigned long flags;
 
@@ -221,7 +221,7 @@
 static int lp_gpio_direction_output(struct gpio_chip *chip,
 				      unsigned offset, int value)
 {
-	struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+	struct lp_gpio *lg = gpiochip_get_data(chip);
 	unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
 	unsigned long flags;
 
@@ -238,7 +238,7 @@
 {
 	struct irq_data *data = irq_desc_get_irq_data(desc);
 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
-	struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
+	struct lp_gpio *lg = gpiochip_get_data(gc);
 	struct irq_chip *chip = irq_data_get_irq_chip(data);
 	u32 base, pin, mask;
 	unsigned long reg, ena, pending;
@@ -273,7 +273,7 @@
 static void lp_irq_enable(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
+	struct lp_gpio *lg = gpiochip_get_data(gc);
 	u32 hwirq = irqd_to_hwirq(d);
 	unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
 	unsigned long flags;
@@ -286,7 +286,7 @@
 static void lp_irq_disable(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
+	struct lp_gpio *lg = gpiochip_get_data(gc);
 	u32 hwirq = irqd_to_hwirq(d);
 	unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
 	unsigned long flags;
@@ -368,9 +368,9 @@
 	gc->base = -1;
 	gc->ngpio = LP_NUM_GPIO;
 	gc->can_sleep = false;
-	gc->dev = dev;
+	gc->parent = dev;
 
-	ret = gpiochip_add(gc);
+	ret = gpiochip_add_data(gc, lg);
 	if (ret) {
 		dev_err(dev, "failed adding lp-gpio chip\n");
 		return ret;
diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/gpio-max7300.c
index 0cc2c27..1ae9ba8 100644
--- a/drivers/gpio/gpio-max7300.c
+++ b/drivers/gpio/gpio-max7300.c
@@ -65,7 +65,6 @@
 static struct i2c_driver max7300_driver = {
 	.driver = {
 		.name = "max7300",
-		.owner = THIS_MODULE,
 	},
 	.probe = max7300_probe,
 	.remove = max7300_remove,
diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c
index 0f57d2d..0880736 100644
--- a/drivers/gpio/gpio-max730x.c
+++ b/drivers/gpio/gpio-max730x.c
@@ -50,7 +50,7 @@
 
 static int max7301_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct max7301 *ts = container_of(chip, struct max7301, chip);
+	struct max7301 *ts = gpiochip_get_data(chip);
 	u8 *config;
 	u8 offset_bits, pin_config;
 	int ret;
@@ -92,7 +92,7 @@
 static int max7301_direction_output(struct gpio_chip *chip, unsigned offset,
 				    int value)
 {
-	struct max7301 *ts = container_of(chip, struct max7301, chip);
+	struct max7301 *ts = gpiochip_get_data(chip);
 	u8 *config;
 	u8 offset_bits;
 	int ret;
@@ -120,7 +120,7 @@
 
 static int max7301_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct max7301 *ts = container_of(chip, struct max7301, chip);
+	struct max7301 *ts = gpiochip_get_data(chip);
 	int config, level = -EINVAL;
 
 	/* First 4 pins are unused in the controller */
@@ -148,7 +148,7 @@
 
 static void max7301_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct max7301 *ts = container_of(chip, struct max7301, chip);
+	struct max7301 *ts = gpiochip_get_data(chip);
 
 	/* First 4 pins are unused in the controller */
 	offset += 4;
@@ -189,7 +189,7 @@
 
 	ts->chip.ngpio = PIN_NUMBER;
 	ts->chip.can_sleep = true;
-	ts->chip.dev = dev;
+	ts->chip.parent = dev;
 	ts->chip.owner = THIS_MODULE;
 
 	/*
@@ -213,7 +213,7 @@
 		}
 	}
 
-	ret = gpiochip_add(&ts->chip);
+	ret = gpiochip_add_data(&ts->chip, ts);
 	if (ret)
 		goto exit_destroy;
 
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 8c5252c..a9aaf9d 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -158,11 +158,6 @@
 #endif
 };
 
-static inline struct max732x_chip *to_max732x(struct gpio_chip *gc)
-{
-	return container_of(gc, struct max732x_chip, gpio_chip);
-}
-
 static int max732x_writeb(struct max732x_chip *chip, int group_a, uint8_t val)
 {
 	struct i2c_client *client;
@@ -201,21 +196,21 @@
 
 static int max732x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 {
-	struct max732x_chip *chip = to_max732x(gc);
+	struct max732x_chip *chip = gpiochip_get_data(gc);
 	uint8_t reg_val;
 	int ret;
 
 	ret = max732x_readb(chip, is_group_a(chip, off), &reg_val);
 	if (ret < 0)
-		return 0;
+		return ret;
 
-	return reg_val & (1u << (off & 0x7));
+	return !!(reg_val & (1u << (off & 0x7)));
 }
 
 static void max732x_gpio_set_mask(struct gpio_chip *gc, unsigned off, int mask,
 				  int val)
 {
-	struct max732x_chip *chip = to_max732x(gc);
+	struct max732x_chip *chip = gpiochip_get_data(gc);
 	uint8_t reg_out;
 	int ret;
 
@@ -259,7 +254,7 @@
 
 static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
 {
-	struct max732x_chip *chip = to_max732x(gc);
+	struct max732x_chip *chip = gpiochip_get_data(gc);
 	unsigned int mask = 1u << off;
 
 	if ((mask & chip->dir_input) == 0) {
@@ -281,7 +276,7 @@
 static int max732x_gpio_direction_output(struct gpio_chip *gc,
 		unsigned off, int val)
 {
-	struct max732x_chip *chip = to_max732x(gc);
+	struct max732x_chip *chip = gpiochip_get_data(gc);
 	unsigned int mask = 1u << off;
 
 	if ((mask & chip->dir_output) == 0) {
@@ -356,7 +351,7 @@
 static void max732x_irq_mask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct max732x_chip *chip = to_max732x(gc);
+	struct max732x_chip *chip = gpiochip_get_data(gc);
 
 	chip->irq_mask_cur &= ~(1 << d->hwirq);
 }
@@ -364,7 +359,7 @@
 static void max732x_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct max732x_chip *chip = to_max732x(gc);
+	struct max732x_chip *chip = gpiochip_get_data(gc);
 
 	chip->irq_mask_cur |= 1 << d->hwirq;
 }
@@ -372,7 +367,7 @@
 static void max732x_irq_bus_lock(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct max732x_chip *chip = to_max732x(gc);
+	struct max732x_chip *chip = gpiochip_get_data(gc);
 
 	mutex_lock(&chip->irq_lock);
 	chip->irq_mask_cur = chip->irq_mask;
@@ -381,7 +376,7 @@
 static void max732x_irq_bus_sync_unlock(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct max732x_chip *chip = to_max732x(gc);
+	struct max732x_chip *chip = gpiochip_get_data(gc);
 	uint16_t new_irqs;
 	uint16_t level;
 
@@ -400,7 +395,7 @@
 static int max732x_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct max732x_chip *chip = to_max732x(gc);
+	struct max732x_chip *chip = gpiochip_get_data(gc);
 	uint16_t off = d->hwirq;
 	uint16_t mask = 1 << off;
 
@@ -603,7 +598,7 @@
 	gc->base = gpio_start;
 	gc->ngpio = port;
 	gc->label = chip->client->name;
-	gc->dev = &chip->client->dev;
+	gc->parent = &chip->client->dev;
 	gc->owner = THIS_MODULE;
 
 	return port;
@@ -649,7 +644,7 @@
 	chip->client = client;
 
 	nr_port = max732x_setup_gpio(chip, id, pdata->gpio_base);
-	chip->gpio_chip.dev = &client->dev;
+	chip->gpio_chip.parent = &client->dev;
 
 	addr_a = (client->addr & 0x0f) | 0x60;
 	addr_b = (client->addr & 0x0f) | 0x50;
@@ -694,7 +689,7 @@
 			goto out_failed;
 	}
 
-	ret = gpiochip_add(&chip->gpio_chip);
+	ret = gpiochip_add_data(&chip->gpio_chip, chip);
 	if (ret)
 		goto out_failed;
 
@@ -749,7 +744,6 @@
 static struct i2c_driver max732x_driver = {
 	.driver = {
 		.name		= "max732x",
-		.owner		= THIS_MODULE,
 		.of_match_table	= of_match_ptr(max732x_of_table),
 	},
 	.probe		= max732x_probe,
diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c
index ee93c0a..7fffc1d 100644
--- a/drivers/gpio/gpio-mb86s7x.c
+++ b/drivers/gpio/gpio-mb86s7x.c
@@ -44,14 +44,9 @@
 	spinlock_t lock;
 };
 
-static inline struct mb86s70_gpio_chip *chip_to_mb86s70(struct gpio_chip *gc)
-{
-	return container_of(gc, struct mb86s70_gpio_chip, gc);
-}
-
 static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio)
 {
-	struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+	struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
 	unsigned long flags;
 	u32 val;
 
@@ -73,7 +68,7 @@
 
 static void mb86s70_gpio_free(struct gpio_chip *gc, unsigned gpio)
 {
-	struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+	struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
 	unsigned long flags;
 	u32 val;
 
@@ -88,7 +83,7 @@
 
 static int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
 {
-	struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+	struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
 	unsigned long flags;
 	unsigned char val;
 
@@ -106,7 +101,7 @@
 static int mb86s70_gpio_direction_output(struct gpio_chip *gc,
 					 unsigned gpio, int value)
 {
-	struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+	struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
 	unsigned long flags;
 	unsigned char val;
 
@@ -130,14 +125,14 @@
 
 static int mb86s70_gpio_get(struct gpio_chip *gc, unsigned gpio)
 {
-	struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+	struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
 
 	return !!(readl(gchip->base + PDR(gpio)) & OFFSET(gpio));
 }
 
 static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value)
 {
-	struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+	struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
 	unsigned long flags;
 	unsigned char val;
 
@@ -187,12 +182,12 @@
 	gchip->gc.label = dev_name(&pdev->dev);
 	gchip->gc.ngpio = 32;
 	gchip->gc.owner = THIS_MODULE;
-	gchip->gc.dev = &pdev->dev;
+	gchip->gc.parent = &pdev->dev;
 	gchip->gc.base = -1;
 
 	platform_set_drvdata(pdev, gchip);
 
-	ret = gpiochip_add(&gchip->gc);
+	ret = gpiochip_add_data(&gchip->gc, gchip);
 	if (ret) {
 		dev_err(&pdev->dev, "couldn't register gpio driver\n");
 		clk_disable_unprepare(gchip->clk);
diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c
index 2853731..0f0df79 100644
--- a/drivers/gpio/gpio-mc33880.c
+++ b/drivers/gpio/gpio-mc33880.c
@@ -71,7 +71,7 @@
 
 static void mc33880_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct mc33880 *mc = container_of(chip, struct mc33880, chip);
+	struct mc33880 *mc = gpiochip_get_data(chip);
 
 	mutex_lock(&mc->lock);
 
@@ -116,7 +116,7 @@
 	mc->chip.base = pdata->base;
 	mc->chip.ngpio = PIN_NUMBER;
 	mc->chip.can_sleep = true;
-	mc->chip.dev = &spi->dev;
+	mc->chip.parent = &spi->dev;
 	mc->chip.owner = THIS_MODULE;
 
 	mc->port_config = 0x00;
@@ -135,7 +135,7 @@
 		goto exit_destroy;
 	}
 
-	ret = gpiochip_add(&mc->chip);
+	ret = gpiochip_add_data(&mc->chip, mc);
 	if (ret)
 		goto exit_destroy;
 
diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c
index d62b4f8..ba22fb9 100644
--- a/drivers/gpio/gpio-mc9s08dz60.c
+++ b/drivers/gpio/gpio-mc9s08dz60.c
@@ -29,12 +29,6 @@
 	struct gpio_chip chip;
 };
 
-static inline struct mc9s08dz60 *to_mc9s08dz60(struct gpio_chip *gc)
-{
-	return container_of(gc, struct mc9s08dz60, chip);
-}
-
-
 static void mc9s_gpio_to_reg_and_bit(int offset, u8 *reg, u8 *bit)
 {
 	*reg = 0x20 + offset / GPIO_NUM_PER_GROUP;
@@ -45,7 +39,7 @@
 {
 	u8 reg, bit;
 	s32 value;
-	struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+	struct mc9s08dz60 *mc9s = gpiochip_get_data(gc);
 
 	mc9s_gpio_to_reg_and_bit(offset, &reg, &bit);
 	value = i2c_smbus_read_byte_data(mc9s->client, reg);
@@ -75,7 +69,7 @@
 
 static void mc9s08dz60_set_value(struct gpio_chip *gc, unsigned offset, int val)
 {
-	struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+	struct mc9s08dz60 *mc9s = gpiochip_get_data(gc);
 
 	mc9s08dz60_set(mc9s, offset, val);
 }
@@ -83,7 +77,7 @@
 static int mc9s08dz60_direction_output(struct gpio_chip *gc,
 				       unsigned offset, int val)
 {
-	struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+	struct mc9s08dz60 *mc9s = gpiochip_get_data(gc);
 
 	return mc9s08dz60_set(mc9s, offset, val);
 }
@@ -99,7 +93,7 @@
 
 	mc9s->chip.label = client->name;
 	mc9s->chip.base = -1;
-	mc9s->chip.dev = &client->dev;
+	mc9s->chip.parent = &client->dev;
 	mc9s->chip.owner = THIS_MODULE;
 	mc9s->chip.ngpio = GPIO_NUM;
 	mc9s->chip.can_sleep = true;
@@ -109,7 +103,7 @@
 	mc9s->client = client;
 	i2c_set_clientdata(client, mc9s);
 
-	return gpiochip_add(&mc9s->chip);
+	return gpiochip_add_data(&mc9s->chip, mc9s);
 }
 
 static int mc9s08dz60_remove(struct i2c_client *client)
@@ -131,7 +125,6 @@
 
 static struct i2c_driver mc9s08dz60_i2c_driver = {
 	.driver = {
-		.owner = THIS_MODULE,
 		.name = "mc9s08dz60",
 	},
 	.probe = mc9s08dz60_probe,
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index 4a41694..c767879 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -269,7 +269,7 @@
 
 static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct mcp23s08	*mcp = container_of(chip, struct mcp23s08, chip);
+	struct mcp23s08	*mcp = gpiochip_get_data(chip);
 	int status;
 
 	mutex_lock(&mcp->lock);
@@ -281,7 +281,7 @@
 
 static int mcp23s08_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct mcp23s08	*mcp = container_of(chip, struct mcp23s08, chip);
+	struct mcp23s08	*mcp = gpiochip_get_data(chip);
 	int status;
 
 	mutex_lock(&mcp->lock);
@@ -312,7 +312,7 @@
 
 static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct mcp23s08	*mcp = container_of(chip, struct mcp23s08, chip);
+	struct mcp23s08	*mcp = gpiochip_get_data(chip);
 	unsigned mask = 1 << offset;
 
 	mutex_lock(&mcp->lock);
@@ -323,7 +323,7 @@
 static int
 mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct mcp23s08	*mcp = container_of(chip, struct mcp23s08, chip);
+	struct mcp23s08	*mcp = gpiochip_get_data(chip);
 	unsigned mask = 1 << offset;
 	int status;
 
@@ -377,7 +377,7 @@
 
 static int mcp23s08_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
+	struct mcp23s08 *mcp = gpiochip_get_data(chip);
 
 	return irq_find_mapping(mcp->irq_domain, offset);
 }
@@ -446,7 +446,7 @@
 	struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
 
 	if (gpiochip_lock_as_irq(&mcp->chip, data->hwirq)) {
-		dev_err(mcp->chip.dev,
+		dev_err(mcp->chip.parent,
 			"unable to lock HW IRQ %lu for IRQ usage\n",
 			data->hwirq);
 		return -EINVAL;
@@ -481,7 +481,8 @@
 
 	mutex_init(&mcp->irq_lock);
 
-	mcp->irq_domain = irq_domain_add_linear(chip->dev->of_node, chip->ngpio,
+	mcp->irq_domain = irq_domain_add_linear(chip->parent->of_node,
+						chip->ngpio,
 						&irq_domain_simple_ops, mcp);
 	if (!mcp->irq_domain)
 		return -ENODEV;
@@ -491,10 +492,11 @@
 	else
 		irqflags |= IRQF_TRIGGER_LOW;
 
-	err = devm_request_threaded_irq(chip->dev, mcp->irq, NULL, mcp23s08_irq,
-					irqflags, dev_name(chip->dev), mcp);
+	err = devm_request_threaded_irq(chip->parent, mcp->irq, NULL,
+					mcp23s08_irq,
+					irqflags, dev_name(chip->parent), mcp);
 	if (err != 0) {
-		dev_err(chip->dev, "unable to request IRQ#%d: %d\n",
+		dev_err(chip->parent, "unable to request IRQ#%d: %d\n",
 			mcp->irq, err);
 		return err;
 	}
@@ -542,7 +544,7 @@
 	int		t;
 	unsigned	mask;
 
-	mcp = container_of(chip, struct mcp23s08, chip);
+	mcp = gpiochip_get_data(chip);
 
 	/* NOTE: we only handle one bank for now ... */
 	bank = '0' + ((mcp->addr >> 1) & 0x7);
@@ -638,7 +640,7 @@
 
 	mcp->chip.base = pdata->base;
 	mcp->chip.can_sleep = true;
-	mcp->chip.dev = dev;
+	mcp->chip.parent = dev;
 	mcp->chip.owner = THIS_MODULE;
 
 	/* verify MCP_IOCON.SEQOP = 0, so sequential reads work,
@@ -652,7 +654,7 @@
 	mcp->irq_controller = pdata->irq_controller;
 	if (mcp->irq && mcp->irq_controller) {
 		mcp->irq_active_high =
-			of_property_read_bool(mcp->chip.dev->of_node,
+			of_property_read_bool(mcp->chip.parent->of_node,
 					      "microchip,irq-active-high");
 
 		if (type == MCP_TYPE_017)
@@ -702,7 +704,7 @@
 			goto fail;
 	}
 
-	status = gpiochip_add(&mcp->chip);
+	status = gpiochip_add_data(&mcp->chip, mcp);
 	if (status < 0)
 		goto fail;
 
diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c
index 5536108..796a5a4 100644
--- a/drivers/gpio/gpio-ml-ioh.c
+++ b/drivers/gpio/gpio-ml-ioh.c
@@ -106,7 +106,7 @@
 static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
 {
 	u32 reg_val;
-	struct ioh_gpio *chip =	container_of(gpio, struct ioh_gpio, gpio);
+	struct ioh_gpio *chip =	gpiochip_get_data(gpio);
 	unsigned long flags;
 
 	spin_lock_irqsave(&chip->spinlock, flags);
@@ -122,15 +122,15 @@
 
 static int ioh_gpio_get(struct gpio_chip *gpio, unsigned nr)
 {
-	struct ioh_gpio *chip =	container_of(gpio, struct ioh_gpio, gpio);
+	struct ioh_gpio *chip =	gpiochip_get_data(gpio);
 
-	return ioread32(&chip->reg->regs[chip->ch].pi) & (1 << nr);
+	return !!(ioread32(&chip->reg->regs[chip->ch].pi) & (1 << nr));
 }
 
 static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
 				     int val)
 {
-	struct ioh_gpio *chip =	container_of(gpio, struct ioh_gpio, gpio);
+	struct ioh_gpio *chip =	gpiochip_get_data(gpio);
 	u32 pm;
 	u32 reg_val;
 	unsigned long flags;
@@ -155,7 +155,7 @@
 
 static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
 {
-	struct ioh_gpio *chip =	container_of(gpio, struct ioh_gpio, gpio);
+	struct ioh_gpio *chip =	gpiochip_get_data(gpio);
 	u32 pm;
 	unsigned long flags;
 
@@ -225,7 +225,7 @@
 
 static int ioh_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
 {
-	struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
+	struct ioh_gpio *chip = gpiochip_get_data(gpio);
 	return chip->irq_base + offset;
 }
 
@@ -450,7 +450,7 @@
 		chip->ch = i;
 		spin_lock_init(&chip->spinlock);
 		ioh_gpio_setup(chip, num_ports[i]);
-		ret = gpiochip_add(&chip->gpio);
+		ret = gpiochip_add_data(&chip->gpio, chip);
 		if (ret) {
 			dev_err(&pdev->dev, "IOH gpio: Failed to register GPIO\n");
 			goto err_gpiochip_add;
diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c
index f67ef22..54e5d82 100644
--- a/drivers/gpio/gpio-mm-lantiq.c
+++ b/drivers/gpio/gpio-mm-lantiq.c
@@ -61,9 +61,7 @@
  */
 static void ltq_mm_set(struct gpio_chip *gc, unsigned offset, int value)
 {
-	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-	struct ltq_mm *chip =
-		container_of(mm_gc, struct ltq_mm, mmchip);
+	struct ltq_mm *chip = gpiochip_get_data(gc);
 
 	if (value)
 		chip->shadow |= (1 << offset);
@@ -122,7 +120,7 @@
 	if (!of_property_read_u32(pdev->dev.of_node, "lantiq,shadow", &shadow))
 		chip->shadow = shadow;
 
-	return of_mm_gpiochip_add(pdev->dev.of_node, &chip->mmchip);
+	return of_mm_gpiochip_add_data(pdev->dev.of_node, &chip->mmchip, chip);
 }
 
 static int ltq_mm_remove(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c
index d3355a6..ca60453 100644
--- a/drivers/gpio/gpio-moxart.c
+++ b/drivers/gpio/gpio-moxart.c
@@ -14,7 +14,6 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/io.h>
-#include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
@@ -23,7 +22,7 @@
 #include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/bitops.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
 
 #define GPIO_DATA_OUT		0x00
 #define GPIO_DATA_IN		0x04
@@ -33,12 +32,12 @@
 {
 	struct device *dev = &pdev->dev;
 	struct resource *res;
-	struct bgpio_chip *bgc;
+	struct gpio_chip *gc;
 	void __iomem *base;
 	int ret;
 
-	bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL);
-	if (!bgc)
+	gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
+	if (!gc)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -46,7 +45,7 @@
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
-	ret = bgpio_init(bgc, dev, 4, base + GPIO_DATA_IN,
+	ret = bgpio_init(gc, dev, 4, base + GPIO_DATA_IN,
 			 base + GPIO_DATA_OUT, NULL,
 			 base + GPIO_PIN_DIRECTION, NULL,
 			 BGPIOF_READ_OUTPUT_REG_SET);
@@ -55,16 +54,16 @@
 		return ret;
 	}
 
-	bgc->gc.label = "moxart-gpio";
-	bgc->gc.request = gpiochip_generic_request;
-	bgc->gc.free = gpiochip_generic_free;
-	bgc->data = bgc->read_reg(bgc->reg_set);
-	bgc->gc.base = 0;
-	bgc->gc.ngpio = 32;
-	bgc->gc.dev = dev;
-	bgc->gc.owner = THIS_MODULE;
+	gc->label = "moxart-gpio";
+	gc->request = gpiochip_generic_request;
+	gc->free = gpiochip_generic_free;
+	gc->bgpio_data = gc->read_reg(gc->reg_set);
+	gc->base = 0;
+	gc->ngpio = 32;
+	gc->parent = dev;
+	gc->owner = THIS_MODULE;
 
-	ret = gpiochip_add(&bgc->gc);
+	ret = gpiochip_add_data(gc, NULL);
 	if (ret) {
 		dev_err(dev, "%s: gpiochip_add failed\n",
 			dev->of_node->full_name);
diff --git a/drivers/gpio/gpio-mpc5200.c b/drivers/gpio/gpio-mpc5200.c
index 4c54215..0e5a670 100644
--- a/drivers/gpio/gpio-mpc5200.c
+++ b/drivers/gpio/gpio-mpc5200.c
@@ -71,8 +71,7 @@
 __mpc52xx_wkup_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
 {
 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-	struct mpc52xx_gpiochip *chip = container_of(mm_gc,
-			struct mpc52xx_gpiochip, mmchip);
+	struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc);
 	struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs;
 
 	if (val)
@@ -100,8 +99,7 @@
 static int mpc52xx_wkup_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
 {
 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-	struct mpc52xx_gpiochip *chip = container_of(mm_gc,
-			struct mpc52xx_gpiochip, mmchip);
+	struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc);
 	struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs;
 	unsigned long flags;
 
@@ -125,8 +123,7 @@
 {
 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
 	struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs;
-	struct mpc52xx_gpiochip *chip = container_of(mm_gc,
-			struct mpc52xx_gpiochip, mmchip);
+	struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc);
 	unsigned long flags;
 
 	spin_lock_irqsave(&gpio_lock, flags);
@@ -169,7 +166,7 @@
 	gc->get              = mpc52xx_wkup_gpio_get;
 	gc->set              = mpc52xx_wkup_gpio_set;
 
-	ret = of_mm_gpiochip_add(ofdev->dev.of_node, &chip->mmchip);
+	ret = of_mm_gpiochip_add_data(ofdev->dev.of_node, &chip->mmchip, chip);
 	if (ret)
 		return ret;
 
@@ -236,8 +233,7 @@
 __mpc52xx_simple_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
 {
 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-	struct mpc52xx_gpiochip *chip = container_of(mm_gc,
-			struct mpc52xx_gpiochip, mmchip);
+	struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc);
 	struct mpc52xx_gpio __iomem *regs = mm_gc->regs;
 
 	if (val)
@@ -264,8 +260,7 @@
 static int mpc52xx_simple_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
 {
 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-	struct mpc52xx_gpiochip *chip = container_of(mm_gc,
-			struct mpc52xx_gpiochip, mmchip);
+	struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc);
 	struct mpc52xx_gpio __iomem *regs = mm_gc->regs;
 	unsigned long flags;
 
@@ -288,8 +283,7 @@
 mpc52xx_simple_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 {
 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-	struct mpc52xx_gpiochip *chip = container_of(mm_gc,
-			struct mpc52xx_gpiochip, mmchip);
+	struct mpc52xx_gpiochip *chip = gpiochip_get_data(gc);
 	struct mpc52xx_gpio __iomem *regs = mm_gc->regs;
 	unsigned long flags;
 
@@ -334,7 +328,7 @@
 	gc->get              = mpc52xx_simple_gpio_get;
 	gc->set              = mpc52xx_simple_gpio_set;
 
-	ret = of_mm_gpiochip_add(ofdev->dev.of_node, &chip->mmchip);
+	ret = of_mm_gpiochip_add_data(ofdev->dev.of_node, &chip->mmchip, chip);
 	if (ret)
 		return ret;
 
@@ -360,15 +354,14 @@
 	.remove = mpc52xx_gpiochip_remove,
 };
 
+static struct platform_driver * const drivers[] = {
+	&mpc52xx_wkup_gpiochip_driver,
+	&mpc52xx_simple_gpiochip_driver,
+};
+
 static int __init mpc52xx_gpio_init(void)
 {
-	if (platform_driver_register(&mpc52xx_wkup_gpiochip_driver))
-		printk(KERN_ERR "Unable to register wakeup GPIO driver\n");
-
-	if (platform_driver_register(&mpc52xx_simple_gpiochip_driver))
-		printk(KERN_ERR "Unable to register simple GPIO driver\n");
-
-	return 0;
+	return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
 }
 
 /* Make sure we get initialised before anyone else tries to use us */
@@ -376,9 +369,7 @@
 
 static void __exit mpc52xx_gpio_exit(void)
 {
-	platform_driver_unregister(&mpc52xx_wkup_gpiochip_driver);
-
-	platform_driver_unregister(&mpc52xx_simple_gpiochip_driver);
+	platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
 }
 module_exit(mpc52xx_gpio_exit);
 
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index 48ef368..9d40787 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -49,15 +49,10 @@
 	return 1u << (MPC8XXX_GPIO_PINS - 1 - gpio);
 }
 
-static inline struct mpc8xxx_gpio_chip *
-to_mpc8xxx_gpio_chip(struct of_mm_gpio_chip *mm)
-{
-	return container_of(mm, struct mpc8xxx_gpio_chip, mm_gc);
-}
-
 static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm)
 {
-	struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+	struct mpc8xxx_gpio_chip *mpc8xxx_gc =
+		container_of(mm, struct mpc8xxx_gpio_chip, mm_gc);
 
 	mpc8xxx_gc->data = in_be32(mm->regs + GPIO_DAT);
 }
@@ -71,7 +66,7 @@
 {
 	u32 val;
 	struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
-	struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+	struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
 	u32 out_mask, out_shadow;
 
 	out_mask = in_be32(mm->regs + GPIO_DIR);
@@ -79,7 +74,7 @@
 	val = in_be32(mm->regs + GPIO_DAT) & ~out_mask;
 	out_shadow = mpc8xxx_gc->data & out_mask;
 
-	return (val | out_shadow) & mpc8xxx_gpio2mask(gpio);
+	return !!((val | out_shadow) & mpc8xxx_gpio2mask(gpio));
 }
 
 static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
@@ -92,7 +87,7 @@
 static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
 {
 	struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
-	struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+	struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
@@ -111,7 +106,7 @@
 				      unsigned long *mask, unsigned long *bits)
 {
 	struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
-	struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+	struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
 	unsigned long flags;
 	int i;
 
@@ -136,7 +131,7 @@
 static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
 {
 	struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
-	struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+	struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
@@ -151,7 +146,7 @@
 static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 {
 	struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
-	struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+	struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
 	unsigned long flags;
 
 	mpc8xxx_gpio_set(gc, gpio, val);
@@ -185,8 +180,7 @@
 
 static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 {
-	struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
-	struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+	struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
 
 	if (mpc8xxx_gc->irq && offset < MPC8XXX_GPIO_PINS)
 		return irq_create_mapping(mpc8xxx_gc->irq, offset);
@@ -417,7 +411,7 @@
 	gc->set_multiple = mpc8xxx_gpio_set_multiple;
 	gc->to_irq = mpc8xxx_gpio_to_irq;
 
-	ret = of_mm_gpiochip_add(np, mm_gc);
+	ret = of_mm_gpiochip_add_data(np, mm_gc, mpc8xxx_gc);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c
index 22523aa..d756497 100644
--- a/drivers/gpio/gpio-msic.c
+++ b/drivers/gpio/gpio-msic.c
@@ -143,7 +143,7 @@
 	if (ret < 0)
 		return ret;
 
-	return r & MSIC_GPIO_DIN_MASK;
+	return !!(r & MSIC_GPIO_DIN_MASK);
 }
 
 static void msic_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -179,7 +179,7 @@
 
 static int msic_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct msic_gpio *mg = container_of(chip, struct msic_gpio, chip);
+	struct msic_gpio *mg = gpiochip_get_data(chip);
 	return mg->irq_base + offset;
 }
 
@@ -293,11 +293,11 @@
 	mg->chip.base = pdata->gpio_base;
 	mg->chip.ngpio = MSIC_NUM_GPIO;
 	mg->chip.can_sleep = true;
-	mg->chip.dev = dev;
+	mg->chip.parent = dev;
 
 	mutex_init(&mg->buslock);
 
-	retval = gpiochip_add(&mg->chip);
+	retval = gpiochip_add_data(&mg->chip, mg);
 	if (retval) {
 		dev_err(dev, "Adding MSIC gpio chip failed\n");
 		goto err;
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index d428b97..a5eacc1 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -187,8 +187,7 @@
 
 static void mvebu_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
 {
-	struct mvebu_gpio_chip *mvchip =
-		container_of(chip, struct mvebu_gpio_chip, chip);
+	struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
 	unsigned long flags;
 	u32 u;
 
@@ -204,8 +203,7 @@
 
 static int mvebu_gpio_get(struct gpio_chip *chip, unsigned pin)
 {
-	struct mvebu_gpio_chip *mvchip =
-		container_of(chip, struct mvebu_gpio_chip, chip);
+	struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
 	u32 u;
 
 	if (readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & (1 << pin)) {
@@ -220,8 +218,7 @@
 
 static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value)
 {
-	struct mvebu_gpio_chip *mvchip =
-		container_of(chip, struct mvebu_gpio_chip, chip);
+	struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
 	unsigned long flags;
 	u32 u;
 
@@ -237,8 +234,7 @@
 
 static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
 {
-	struct mvebu_gpio_chip *mvchip =
-		container_of(chip, struct mvebu_gpio_chip, chip);
+	struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
 	unsigned long flags;
 	int ret;
 	u32 u;
@@ -261,8 +257,7 @@
 static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin,
 				       int value)
 {
-	struct mvebu_gpio_chip *mvchip =
-		container_of(chip, struct mvebu_gpio_chip, chip);
+	struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
 	unsigned long flags;
 	int ret;
 	u32 u;
@@ -287,8 +282,7 @@
 
 static int mvebu_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
 {
-	struct mvebu_gpio_chip *mvchip =
-		container_of(chip, struct mvebu_gpio_chip, chip);
+	struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
 	return irq_create_mapping(mvchip->domain, pin);
 }
 
@@ -494,8 +488,7 @@
 
 static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
-	struct mvebu_gpio_chip *mvchip =
-		container_of(chip, struct mvebu_gpio_chip, chip);
+	struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
 	u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk;
 	int i;
 
@@ -698,7 +691,7 @@
 
 	mvchip->soc_variant = soc_variant;
 	mvchip->chip.label = dev_name(&pdev->dev);
-	mvchip->chip.dev = &pdev->dev;
+	mvchip->chip.parent = &pdev->dev;
 	mvchip->chip.request = gpiochip_generic_request;
 	mvchip->chip.free = gpiochip_generic_free;
 	mvchip->chip.direction_input = mvebu_gpio_direction_input;
@@ -763,7 +756,7 @@
 		BUG();
 	}
 
-	gpiochip_add(&mvchip->chip);
+	gpiochip_add_data(&mvchip->chip, mvchip);
 
 	/* Some gpio controllers do not provide irq support */
 	if (!of_irq_count(np))
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 6ea8df6..7fd21cb 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -26,10 +26,11 @@
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
 #include <linux/irqchip/chained_irq.h>
-#include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
+/* FIXME: for gpio_get_value() replace this with direct register read */
+#include <linux/gpio.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/module.h>
@@ -64,7 +65,7 @@
 	int irq;
 	int irq_high;
 	struct irq_domain *domain;
-	struct bgpio_chip bgc;
+	struct gpio_chip gc;
 	u32 both_edges;
 };
 
@@ -172,7 +173,7 @@
 	struct mxc_gpio_port *port = gc->private;
 	u32 bit, val;
 	u32 gpio_idx = d->hwirq;
-	u32 gpio = port->bgc.gc.base + gpio_idx;
+	u32 gpio = port->gc.base + gpio_idx;
 	int edge;
 	void __iomem *reg = port->base;
 
@@ -398,9 +399,7 @@
 
 static int mxc_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-	struct mxc_gpio_port *port =
-		container_of(bgc, struct mxc_gpio_port, bgc);
+	struct mxc_gpio_port *port = gpiochip_get_data(gc);
 
 	return irq_find_mapping(port->domain, offset);
 }
@@ -451,7 +450,7 @@
 							 port);
 	}
 
-	err = bgpio_init(&port->bgc, &pdev->dev, 4,
+	err = bgpio_init(&port->gc, &pdev->dev, 4,
 			 port->base + GPIO_PSR,
 			 port->base + GPIO_DR, NULL,
 			 port->base + GPIO_GDIR, NULL,
@@ -459,13 +458,13 @@
 	if (err)
 		goto out_bgio;
 
-	port->bgc.gc.to_irq = mxc_gpio_to_irq;
-	port->bgc.gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 :
+	port->gc.to_irq = mxc_gpio_to_irq;
+	port->gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 :
 					     pdev->id * 32;
 
-	err = gpiochip_add(&port->bgc.gc);
+	err = gpiochip_add_data(&port->gc, port);
 	if (err)
-		goto out_bgpio_remove;
+		goto out_bgio;
 
 	irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
 	if (irq_base < 0) {
@@ -494,9 +493,7 @@
 out_irqdesc_free:
 	irq_free_descs(irq_base, 32);
 out_gpiochip_remove:
-	gpiochip_remove(&port->bgc.gc);
-out_bgpio_remove:
-	bgpio_remove(&port->bgc);
+	gpiochip_remove(&port->gc);
 out_bgio:
 	dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err);
 	return err;
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
index a4288f4..b9daa0b 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -26,13 +26,14 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
-#include <linux/gpio.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
+/* FIXME: for gpio_get_value(), replace this by direct register read */
+#include <linux/gpio.h>
 #include <linux/module.h>
 
 #define MXS_SET		0x4
@@ -64,7 +65,7 @@
 	int id;
 	int irq;
 	struct irq_domain *domain;
-	struct bgpio_chip bgc;
+	struct gpio_chip gc;
 	enum mxs_gpio_id devid;
 	u32 both_edges;
 };
@@ -93,7 +94,7 @@
 	port->both_edges &= ~pin_mask;
 	switch (type) {
 	case IRQ_TYPE_EDGE_BOTH:
-		val = gpio_get_value(port->bgc.gc.base + d->hwirq);
+		val = gpio_get_value(port->gc.base + d->hwirq);
 		if (val)
 			edge = GPIO_INT_FALL_EDGE;
 		else
@@ -225,18 +226,14 @@
 
 static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-	struct mxs_gpio_port *port =
-		container_of(bgc, struct mxs_gpio_port, bgc);
+	struct mxs_gpio_port *port = gpiochip_get_data(gc);
 
 	return irq_find_mapping(port->domain, offset);
 }
 
 static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned offset)
 {
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-	struct mxs_gpio_port *port =
-		container_of(bgc, struct mxs_gpio_port, bgc);
+	struct mxs_gpio_port *port = gpiochip_get_data(gc);
 	u32 mask = 1 << offset;
 	u32 dir;
 
@@ -330,26 +327,24 @@
 	irq_set_chained_handler_and_data(port->irq, mxs_gpio_irq_handler,
 					 port);
 
-	err = bgpio_init(&port->bgc, &pdev->dev, 4,
+	err = bgpio_init(&port->gc, &pdev->dev, 4,
 			 port->base + PINCTRL_DIN(port),
 			 port->base + PINCTRL_DOUT(port) + MXS_SET,
 			 port->base + PINCTRL_DOUT(port) + MXS_CLR,
 			 port->base + PINCTRL_DOE(port), NULL, 0);
 	if (err)
-		goto out_irqdesc_free;
+		goto out_irqdomain_remove;
 
-	port->bgc.gc.to_irq = mxs_gpio_to_irq;
-	port->bgc.gc.get_direction = mxs_gpio_get_direction;
-	port->bgc.gc.base = port->id * 32;
+	port->gc.to_irq = mxs_gpio_to_irq;
+	port->gc.get_direction = mxs_gpio_get_direction;
+	port->gc.base = port->id * 32;
 
-	err = gpiochip_add(&port->bgc.gc);
+	err = gpiochip_add_data(&port->gc, port);
 	if (err)
-		goto out_bgpio_remove;
+		goto out_irqdomain_remove;
 
 	return 0;
 
-out_bgpio_remove:
-	bgpio_remove(&port->bgc);
 out_irqdomain_remove:
 	irq_domain_remove(port->domain);
 out_irqdesc_free:
diff --git a/drivers/gpio/gpio-octeon.c b/drivers/gpio/gpio-octeon.c
index 62ae251..7665ebc 100644
--- a/drivers/gpio/gpio-octeon.c
+++ b/drivers/gpio/gpio-octeon.c
@@ -41,7 +41,7 @@
 
 static int octeon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
 {
-	struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+	struct octeon_gpio *gpio = gpiochip_get_data(chip);
 
 	cvmx_write_csr(gpio->register_base + bit_cfg_reg(offset), 0);
 	return 0;
@@ -49,7 +49,7 @@
 
 static void octeon_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+	struct octeon_gpio *gpio = gpiochip_get_data(chip);
 	u64 mask = 1ull << offset;
 	u64 reg = gpio->register_base + (value ? TX_SET : TX_CLEAR);
 	cvmx_write_csr(reg, mask);
@@ -58,7 +58,7 @@
 static int octeon_gpio_dir_out(struct gpio_chip *chip, unsigned offset,
 			       int value)
 {
-	struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+	struct octeon_gpio *gpio = gpiochip_get_data(chip);
 	union cvmx_gpio_bit_cfgx cfgx;
 
 	octeon_gpio_set(chip, offset, value);
@@ -72,7 +72,7 @@
 
 static int octeon_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+	struct octeon_gpio *gpio = gpiochip_get_data(chip);
 	u64 read_bits = cvmx_read_csr(gpio->register_base + RX_DAT);
 
 	return ((1ull << offset) & read_bits) != 0;
@@ -108,7 +108,7 @@
 
 	pdev->dev.platform_data = chip;
 	chip->label = "octeon-gpio";
-	chip->dev = &pdev->dev;
+	chip->parent = &pdev->dev;
 	chip->owner = THIS_MODULE;
 	chip->base = 0;
 	chip->can_sleep = false;
@@ -117,7 +117,7 @@
 	chip->get = octeon_gpio_get;
 	chip->direction_output = octeon_gpio_dir_out;
 	chip->set = octeon_gpio_set;
-	err = gpiochip_add(chip);
+	err = gpiochip_add_data(chip, gpio);
 	if (err)
 		goto out;
 
@@ -128,7 +128,7 @@
 
 static int octeon_gpio_remove(struct platform_device *pdev)
 {
-	struct gpio_chip *chip = pdev->dev.platform_data;
+	struct gpio_chip *chip = dev_get_platdata(&pdev->dev);
 	gpiochip_remove(chip);
 	return 0;
 }
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index f7fbb46..189f672 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -93,7 +93,7 @@
 static inline struct gpio_bank *omap_irq_data_get_bank(struct irq_data *d)
 {
 	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
-	return container_of(chip, struct gpio_bank, chip);
+	return gpiochip_get_data(chip);
 }
 
 static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio,
@@ -661,7 +661,7 @@
 
 static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
-	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+	struct gpio_bank *bank = gpiochip_get_data(chip);
 	unsigned long flags;
 
 	/*
@@ -681,7 +681,7 @@
 
 static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
-	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+	struct gpio_bank *bank = gpiochip_get_data(chip);
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&bank->lock, flags);
@@ -954,7 +954,7 @@
 	void __iomem *reg;
 	int dir;
 
-	bank = container_of(chip, struct gpio_bank, chip);
+	bank = gpiochip_get_data(chip);
 	reg = bank->base + bank->regs->direction;
 	raw_spin_lock_irqsave(&bank->lock, flags);
 	dir = !!(readl_relaxed(reg) & BIT(offset));
@@ -967,7 +967,7 @@
 	struct gpio_bank *bank;
 	unsigned long flags;
 
-	bank = container_of(chip, struct gpio_bank, chip);
+	bank = gpiochip_get_data(chip);
 	raw_spin_lock_irqsave(&bank->lock, flags);
 	omap_set_gpio_direction(bank, offset, 1);
 	raw_spin_unlock_irqrestore(&bank->lock, flags);
@@ -978,7 +978,7 @@
 {
 	struct gpio_bank *bank;
 
-	bank = container_of(chip, struct gpio_bank, chip);
+	bank = gpiochip_get_data(chip);
 
 	if (omap_gpio_is_input(bank, offset))
 		return omap_get_gpio_datain(bank, offset);
@@ -991,7 +991,7 @@
 	struct gpio_bank *bank;
 	unsigned long flags;
 
-	bank = container_of(chip, struct gpio_bank, chip);
+	bank = gpiochip_get_data(chip);
 	raw_spin_lock_irqsave(&bank->lock, flags);
 	bank->set_dataout(bank, offset, value);
 	omap_set_gpio_direction(bank, offset, 0);
@@ -1005,7 +1005,7 @@
 	struct gpio_bank *bank;
 	unsigned long flags;
 
-	bank = container_of(chip, struct gpio_bank, chip);
+	bank = gpiochip_get_data(chip);
 
 	raw_spin_lock_irqsave(&bank->lock, flags);
 	omap2_set_gpio_debounce(bank, offset, debounce);
@@ -1019,7 +1019,7 @@
 	struct gpio_bank *bank;
 	unsigned long flags;
 
-	bank = container_of(chip, struct gpio_bank, chip);
+	bank = gpiochip_get_data(chip);
 	raw_spin_lock_irqsave(&bank->lock, flags);
 	bank->set_dataout(bank, offset, value);
 	raw_spin_unlock_irqrestore(&bank->lock, flags);
@@ -1090,7 +1090,7 @@
 	if (bank->is_mpuio) {
 		bank->chip.label = "mpuio";
 		if (bank->regs->wkup_en)
-			bank->chip.dev = &omap_mpuio_device.dev;
+			bank->chip.parent = &omap_mpuio_device.dev;
 		bank->chip.base = OMAP_MPUIO(0);
 	} else {
 		bank->chip.label = "gpio";
@@ -1098,7 +1098,7 @@
 	}
 	bank->chip.ngpio = bank->width;
 
-	ret = gpiochip_add(&bank->chip);
+	ret = gpiochip_add_data(&bank->chip, bank);
 	if (ret) {
 		dev_err(bank->dev, "Could not register gpio chip %d\n", ret);
 		return ret;
@@ -1197,7 +1197,7 @@
 	}
 
 	bank->dev = dev;
-	bank->chip.dev = dev;
+	bank->chip.parent = dev;
 	bank->chip.owner = THIS_MODULE;
 	bank->dbck_flag = pdata->dbck_flag;
 	bank->stride = pdata->bank_stride;
diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c
index 52b447c..fdfb3b1 100644
--- a/drivers/gpio/gpio-palmas.c
+++ b/drivers/gpio/gpio-palmas.c
@@ -35,14 +35,9 @@
 	int ngpio;
 };
 
-static inline struct palmas_gpio *to_palmas_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct palmas_gpio, gpio_chip);
-}
-
 static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)
 {
-	struct palmas_gpio *pg = to_palmas_gpio(gc);
+	struct palmas_gpio *pg = gpiochip_get_data(gc);
 	struct palmas *palmas = pg->palmas;
 	unsigned int val;
 	int ret;
@@ -54,7 +49,7 @@
 
 	ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);
 	if (ret < 0) {
-		dev_err(gc->dev, "Reg 0x%02x read failed, %d\n", reg, ret);
+		dev_err(gc->parent, "Reg 0x%02x read failed, %d\n", reg, ret);
 		return ret;
 	}
 
@@ -65,7 +60,7 @@
 
 	ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);
 	if (ret < 0) {
-		dev_err(gc->dev, "Reg 0x%02x read failed, %d\n", reg, ret);
+		dev_err(gc->parent, "Reg 0x%02x read failed, %d\n", reg, ret);
 		return ret;
 	}
 	return !!(val & BIT(offset));
@@ -74,7 +69,7 @@
 static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset,
 			int value)
 {
-	struct palmas_gpio *pg = to_palmas_gpio(gc);
+	struct palmas_gpio *pg = gpiochip_get_data(gc);
 	struct palmas *palmas = pg->palmas;
 	int ret;
 	unsigned int reg;
@@ -90,13 +85,13 @@
 
 	ret = palmas_write(palmas, PALMAS_GPIO_BASE, reg, BIT(offset));
 	if (ret < 0)
-		dev_err(gc->dev, "Reg 0x%02x write failed, %d\n", reg, ret);
+		dev_err(gc->parent, "Reg 0x%02x write failed, %d\n", reg, ret);
 }
 
 static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset,
 				int value)
 {
-	struct palmas_gpio *pg = to_palmas_gpio(gc);
+	struct palmas_gpio *pg = gpiochip_get_data(gc);
 	struct palmas *palmas = pg->palmas;
 	int ret;
 	unsigned int reg;
@@ -111,13 +106,14 @@
 	ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg,
 				BIT(offset), BIT(offset));
 	if (ret < 0)
-		dev_err(gc->dev, "Reg 0x%02x update failed, %d\n", reg, ret);
+		dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg,
+			ret);
 	return ret;
 }
 
 static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset)
 {
-	struct palmas_gpio *pg = to_palmas_gpio(gc);
+	struct palmas_gpio *pg = gpiochip_get_data(gc);
 	struct palmas *palmas = pg->palmas;
 	int ret;
 	unsigned int reg;
@@ -128,13 +124,14 @@
 
 	ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, BIT(offset), 0);
 	if (ret < 0)
-		dev_err(gc->dev, "Reg 0x%02x update failed, %d\n", reg, ret);
+		dev_err(gc->parent, "Reg 0x%02x update failed, %d\n", reg,
+			ret);
 	return ret;
 }
 
 static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 {
-	struct palmas_gpio *pg = to_palmas_gpio(gc);
+	struct palmas_gpio *pg = gpiochip_get_data(gc);
 	struct palmas *palmas = pg->palmas;
 
 	return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset);
@@ -188,7 +185,7 @@
 	palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq;
 	palmas_gpio->gpio_chip.set	= palmas_gpio_set;
 	palmas_gpio->gpio_chip.get	= palmas_gpio_get;
-	palmas_gpio->gpio_chip.dev = &pdev->dev;
+	palmas_gpio->gpio_chip.parent = &pdev->dev;
 #ifdef CONFIG_OF_GPIO
 	palmas_gpio->gpio_chip.of_node = pdev->dev.of_node;
 #endif
@@ -198,7 +195,7 @@
 	else
 		palmas_gpio->gpio_chip.base = -1;
 
-	ret = gpiochip_add(&palmas_gpio->gpio_chip);
+	ret = gpiochip_add_data(&palmas_gpio->gpio_chip, palmas_gpio);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
 		return ret;
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 2d4892c..23196c5 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -18,9 +18,7 @@
 #include <linux/i2c.h>
 #include <linux/platform_data/pca953x.h>
 #include <linux/slab.h>
-#ifdef CONFIG_OF_GPIO
 #include <linux/of_platform.h>
-#endif
 #include <linux/acpi.h>
 
 #define PCA953X_INPUT		0
@@ -109,11 +107,6 @@
 	unsigned long driver_data;
 };
 
-static inline struct pca953x_chip *to_pca(struct gpio_chip *gc)
-{
-	return container_of(gc, struct pca953x_chip, gpio_chip);
-}
-
 static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
 				int off)
 {
@@ -216,7 +209,7 @@
 
 static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
 {
-	struct pca953x_chip *chip = to_pca(gc);
+	struct pca953x_chip *chip = gpiochip_get_data(gc);
 	u8 reg_val;
 	int ret, offset = 0;
 
@@ -245,7 +238,7 @@
 static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 		unsigned off, int val)
 {
-	struct pca953x_chip *chip = to_pca(gc);
+	struct pca953x_chip *chip = gpiochip_get_data(gc);
 	u8 reg_val;
 	int ret, offset = 0;
 
@@ -295,7 +288,7 @@
 
 static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 {
-	struct pca953x_chip *chip = to_pca(gc);
+	struct pca953x_chip *chip = gpiochip_get_data(gc);
 	u32 reg_val;
 	int ret, offset = 0;
 
@@ -323,7 +316,7 @@
 
 static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 {
-	struct pca953x_chip *chip = to_pca(gc);
+	struct pca953x_chip *chip = gpiochip_get_data(gc);
 	u8 reg_val;
 	int ret, offset = 0;
 
@@ -352,6 +345,43 @@
 	mutex_unlock(&chip->i2c_lock);
 }
 
+
+static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
+		unsigned long *mask, unsigned long *bits)
+{
+	struct pca953x_chip *chip = gpiochip_get_data(gc);
+	u8 reg_val[MAX_BANK];
+	int ret, offset = 0;
+	int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+	int bank;
+
+	switch (chip->chip_type) {
+	case PCA953X_TYPE:
+		offset = PCA953X_OUTPUT;
+		break;
+	case PCA957X_TYPE:
+		offset = PCA957X_OUT;
+		break;
+	}
+
+	memcpy(reg_val, chip->reg_output, NBANK(chip));
+	mutex_lock(&chip->i2c_lock);
+	for(bank=0; bank<NBANK(chip); bank++) {
+		unsigned bankmask = mask[bank/4] >> ((bank % 4) * 8);
+		if(bankmask) {
+			unsigned bankval  = bits[bank/4] >> ((bank % 4) * 8);
+			reg_val[bank] = (reg_val[bank] & ~bankmask) | bankval;
+		}
+	}
+	ret = i2c_smbus_write_i2c_block_data(chip->client, offset << bank_shift, NBANK(chip), reg_val);
+	if (ret)
+		goto exit;
+
+	memcpy(chip->reg_output, reg_val, NBANK(chip));
+exit:
+	mutex_unlock(&chip->i2c_lock);
+}
+
 static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
 {
 	struct gpio_chip *gc;
@@ -362,12 +392,13 @@
 	gc->direction_output = pca953x_gpio_direction_output;
 	gc->get = pca953x_gpio_get_value;
 	gc->set = pca953x_gpio_set_value;
+	gc->set_multiple = pca953x_gpio_set_multiple;
 	gc->can_sleep = true;
 
 	gc->base = chip->gpio_start;
 	gc->ngpio = gpios;
 	gc->label = chip->client->name;
-	gc->dev = &chip->client->dev;
+	gc->parent = &chip->client->dev;
 	gc->owner = THIS_MODULE;
 	gc->names = chip->names;
 }
@@ -376,7 +407,7 @@
 static void pca953x_irq_mask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct pca953x_chip *chip = to_pca(gc);
+	struct pca953x_chip *chip = gpiochip_get_data(gc);
 
 	chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ));
 }
@@ -384,7 +415,7 @@
 static void pca953x_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct pca953x_chip *chip = to_pca(gc);
+	struct pca953x_chip *chip = gpiochip_get_data(gc);
 
 	chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ);
 }
@@ -392,7 +423,7 @@
 static void pca953x_irq_bus_lock(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct pca953x_chip *chip = to_pca(gc);
+	struct pca953x_chip *chip = gpiochip_get_data(gc);
 
 	mutex_lock(&chip->irq_lock);
 }
@@ -400,7 +431,7 @@
 static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct pca953x_chip *chip = to_pca(gc);
+	struct pca953x_chip *chip = gpiochip_get_data(gc);
 	u8 new_irqs;
 	int level, i;
 
@@ -423,7 +454,7 @@
 static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct pca953x_chip *chip = to_pca(gc);
+	struct pca953x_chip *chip = gpiochip_get_data(gc);
 	int bank_nb = d->hwirq / BANK_SZ;
 	u8 mask = 1 << (d->hwirq % BANK_SZ);
 
@@ -660,6 +691,8 @@
 	return ret;
 }
 
+static const struct of_device_id pca953x_dt_ids[];
+
 static int pca953x_probe(struct i2c_client *client,
 				   const struct i2c_device_id *id)
 {
@@ -691,12 +724,18 @@
 		chip->driver_data = id->driver_data;
 	} else {
 		const struct acpi_device_id *id;
+		const struct of_device_id *match;
 
-		id = acpi_match_device(pca953x_acpi_ids, &client->dev);
-		if (!id)
-			return -ENODEV;
+		match = of_match_device(pca953x_dt_ids, &client->dev);
+		if (match) {
+			chip->driver_data = (int)(uintptr_t)match->data;
+		} else {
+			id = acpi_match_device(pca953x_acpi_ids, &client->dev);
+			if (!id)
+				return -ENODEV;
 
-		chip->driver_data = id->driver_data;
+			chip->driver_data = id->driver_data;
+		}
 	}
 
 	chip->chip_type = PCA_CHIP_TYPE(chip->driver_data);
@@ -715,7 +754,7 @@
 	if (ret)
 		return ret;
 
-	ret = gpiochip_add(&chip->gpio_chip);
+	ret = gpiochip_add_data(&chip->gpio_chip, chip);
 	if (ret)
 		return ret;
 
@@ -755,33 +794,39 @@
 	return 0;
 }
 
+/* convenience to stop overlong match-table lines */
+#define OF_953X(__nrgpio, __int) (void *)(__nrgpio | PCA953X_TYPE | __int)
+#define OF_957X(__nrgpio, __int) (void *)(__nrgpio | PCA957X_TYPE | __int)
+
 static const struct of_device_id pca953x_dt_ids[] = {
-	{ .compatible = "nxp,pca9505", },
-	{ .compatible = "nxp,pca9534", },
-	{ .compatible = "nxp,pca9535", },
-	{ .compatible = "nxp,pca9536", },
-	{ .compatible = "nxp,pca9537", },
-	{ .compatible = "nxp,pca9538", },
-	{ .compatible = "nxp,pca9539", },
-	{ .compatible = "nxp,pca9554", },
-	{ .compatible = "nxp,pca9555", },
-	{ .compatible = "nxp,pca9556", },
-	{ .compatible = "nxp,pca9557", },
-	{ .compatible = "nxp,pca9574", },
-	{ .compatible = "nxp,pca9575", },
-	{ .compatible = "nxp,pca9698", },
+	{ .compatible = "nxp,pca9505", .data = OF_953X(40, PCA_INT), },
+	{ .compatible = "nxp,pca9534", .data = OF_953X( 8, PCA_INT), },
+	{ .compatible = "nxp,pca9535", .data = OF_953X(16, PCA_INT), },
+	{ .compatible = "nxp,pca9536", .data = OF_953X( 4, 0), },
+	{ .compatible = "nxp,pca9537", .data = OF_953X( 4, PCA_INT), },
+	{ .compatible = "nxp,pca9538", .data = OF_953X( 8, PCA_INT), },
+	{ .compatible = "nxp,pca9539", .data = OF_953X(16, PCA_INT), },
+	{ .compatible = "nxp,pca9554", .data = OF_953X( 8, PCA_INT), },
+	{ .compatible = "nxp,pca9555", .data = OF_953X(16, PCA_INT), },
+	{ .compatible = "nxp,pca9556", .data = OF_953X( 8, 0), },
+	{ .compatible = "nxp,pca9557", .data = OF_953X( 8, 0), },
+	{ .compatible = "nxp,pca9574", .data = OF_957X( 8, PCA_INT), },
+	{ .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
+	{ .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
 
-	{ .compatible = "maxim,max7310", },
-	{ .compatible = "maxim,max7312", },
-	{ .compatible = "maxim,max7313", },
-	{ .compatible = "maxim,max7315", },
+	{ .compatible = "maxim,max7310", .data = OF_953X( 8, 0), },
+	{ .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), },
+	{ .compatible = "maxim,max7313", .data = OF_953X(16, PCA_INT), },
+	{ .compatible = "maxim,max7315", .data = OF_953X( 8, PCA_INT), },
 
-	{ .compatible = "ti,pca6107", },
-	{ .compatible = "ti,tca6408", },
-	{ .compatible = "ti,tca6416", },
-	{ .compatible = "ti,tca6424", },
+	{ .compatible = "ti,pca6107", .data = OF_953X( 8, PCA_INT), },
+	{ .compatible = "ti,tca6408", .data = OF_953X( 8, PCA_INT), },
+	{ .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },
+	{ .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), },
 
-	{ .compatible = "exar,xra1202", },
+	{ .compatible = "onsemi,pca9654", .data = OF_953X( 8, PCA_INT), },
+
+	{ .compatible = "exar,xra1202", .data = OF_953X( 8, 0), },
 	{ }
 };
 
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index 1d4d9bc..709cd3f 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -137,7 +137,7 @@
 
 static int pcf857x_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct pcf857x	*gpio = container_of(chip, struct pcf857x, chip);
+	struct pcf857x	*gpio = gpiochip_get_data(chip);
 	int		status;
 
 	mutex_lock(&gpio->lock);
@@ -150,16 +150,16 @@
 
 static int pcf857x_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct pcf857x	*gpio = container_of(chip, struct pcf857x, chip);
+	struct pcf857x	*gpio = gpiochip_get_data(chip);
 	int		value;
 
 	value = gpio->read(gpio->client);
-	return (value < 0) ? 0 : (value & (1 << offset));
+	return (value < 0) ? value : !!(value & (1 << offset));
 }
 
 static int pcf857x_output(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct pcf857x	*gpio = container_of(chip, struct pcf857x, chip);
+	struct pcf857x	*gpio = gpiochip_get_data(chip);
 	unsigned	bit = 1 << offset;
 	int		status;
 
@@ -293,7 +293,7 @@
 
 	gpio->chip.base			= pdata ? pdata->gpio_base : -1;
 	gpio->chip.can_sleep		= true;
-	gpio->chip.dev			= &client->dev;
+	gpio->chip.parent		= &client->dev;
 	gpio->chip.owner		= THIS_MODULE;
 	gpio->chip.get			= pcf857x_get;
 	gpio->chip.set			= pcf857x_set;
@@ -372,7 +372,7 @@
 	gpio->out = ~n_latch;
 	gpio->status = gpio->out;
 
-	status = gpiochip_add(&gpio->chip);
+	status = gpiochip_add_data(&gpio->chip, gpio);
 	if (status < 0)
 		goto fail;
 
@@ -447,7 +447,6 @@
 static struct i2c_driver pcf857x_driver = {
 	.driver = {
 		.name	= "pcf857x",
-		.owner	= THIS_MODULE,
 		.of_match_table = of_match_ptr(pcf857x_of_table),
 	},
 	.probe	= pcf857x_probe,
diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
index 34ed176..7c7135d 100644
--- a/drivers/gpio/gpio-pch.c
+++ b/drivers/gpio/gpio-pch.c
@@ -109,7 +109,7 @@
 static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
 {
 	u32 reg_val;
-	struct pch_gpio *chip =	container_of(gpio, struct pch_gpio, gpio);
+	struct pch_gpio *chip =	gpiochip_get_data(gpio);
 	unsigned long flags;
 
 	spin_lock_irqsave(&chip->spinlock, flags);
@@ -125,15 +125,15 @@
 
 static int pch_gpio_get(struct gpio_chip *gpio, unsigned nr)
 {
-	struct pch_gpio *chip =	container_of(gpio, struct pch_gpio, gpio);
+	struct pch_gpio *chip =	gpiochip_get_data(gpio);
 
-	return ioread32(&chip->reg->pi) & (1 << nr);
+	return (ioread32(&chip->reg->pi) >> nr) & 1;
 }
 
 static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
 				     int val)
 {
-	struct pch_gpio *chip =	container_of(gpio, struct pch_gpio, gpio);
+	struct pch_gpio *chip =	gpiochip_get_data(gpio);
 	u32 pm;
 	u32 reg_val;
 	unsigned long flags;
@@ -158,7 +158,7 @@
 
 static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
 {
-	struct pch_gpio *chip =	container_of(gpio, struct pch_gpio, gpio);
+	struct pch_gpio *chip =	gpiochip_get_data(gpio);
 	u32 pm;
 	unsigned long flags;
 
@@ -211,7 +211,7 @@
 
 static int pch_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
 {
-	struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
+	struct pch_gpio *chip = gpiochip_get_data(gpio);
 	return chip->irq_base + offset;
 }
 
@@ -220,7 +220,7 @@
 	struct gpio_chip *gpio = &chip->gpio;
 
 	gpio->label = dev_name(chip->dev);
-	gpio->dev = chip->dev;
+	gpio->parent = chip->dev;
 	gpio->owner = THIS_MODULE;
 	gpio->direction_input = pch_gpio_direction_input;
 	gpio->get = pch_gpio_get;
@@ -394,7 +394,10 @@
 	pci_set_drvdata(pdev, chip);
 	spin_lock_init(&chip->spinlock);
 	pch_gpio_setup(chip);
-	ret = gpiochip_add(&chip->gpio);
+#ifdef CONFIG_OF_GPIO
+	chip->gpio.of_node = pdev->dev.of_node;
+#endif
+	ret = gpiochip_add_data(&chip->gpio, chip);
 	if (ret) {
 		dev_err(&pdev->dev, "PCH gpio: Failed to register GPIO\n");
 		goto err_gpiochip_add;
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 4d4b376..5cb3821 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
+#include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/bitops.h>
@@ -60,7 +61,7 @@
 
 static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
 {
-	struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+	struct pl061_gpio *chip = gpiochip_get_data(gc);
 	unsigned long flags;
 	unsigned char gpiodir;
 
@@ -79,7 +80,7 @@
 static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
 		int value)
 {
-	struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+	struct pl061_gpio *chip = gpiochip_get_data(gc);
 	unsigned long flags;
 	unsigned char gpiodir;
 
@@ -104,14 +105,14 @@
 
 static int pl061_get_value(struct gpio_chip *gc, unsigned offset)
 {
-	struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+	struct pl061_gpio *chip = gpiochip_get_data(gc);
 
 	return !!readb(chip->base + (BIT(offset + 2)));
 }
 
 static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value)
 {
-	struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+	struct pl061_gpio *chip = gpiochip_get_data(gc);
 
 	writeb(!!value << offset, chip->base + (BIT(offset + 2)));
 }
@@ -119,7 +120,7 @@
 static int pl061_irq_type(struct irq_data *d, unsigned trigger)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+	struct pl061_gpio *chip = gpiochip_get_data(gc);
 	int offset = irqd_to_hwirq(d);
 	unsigned long flags;
 	u8 gpiois, gpioibe, gpioiev;
@@ -131,7 +132,7 @@
 	if ((trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) &&
 	    (trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)))
 	{
-		dev_err(gc->dev,
+		dev_err(gc->parent,
 			"trying to configure line %d for both level and edge "
 			"detection, choose one!\n",
 			offset);
@@ -158,7 +159,7 @@
 		else
 			gpioiev &= ~bit;
 		irq_set_handler_locked(d, handle_level_irq);
-		dev_dbg(gc->dev, "line %d: IRQ on %s level\n",
+		dev_dbg(gc->parent, "line %d: IRQ on %s level\n",
 			offset,
 			polarity ? "HIGH" : "LOW");
 	} else if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
@@ -167,7 +168,7 @@
 		/* Select both edges, setting this makes GPIOEV be ignored */
 		gpioibe |= bit;
 		irq_set_handler_locked(d, handle_edge_irq);
-		dev_dbg(gc->dev, "line %d: IRQ on both edges\n", offset);
+		dev_dbg(gc->parent, "line %d: IRQ on both edges\n", offset);
 	} else if ((trigger & IRQ_TYPE_EDGE_RISING) ||
 		   (trigger & IRQ_TYPE_EDGE_FALLING)) {
 		bool rising = trigger & IRQ_TYPE_EDGE_RISING;
@@ -182,7 +183,7 @@
 		else
 			gpioiev &= ~bit;
 		irq_set_handler_locked(d, handle_edge_irq);
-		dev_dbg(gc->dev, "line %d: IRQ on %s edge\n",
+		dev_dbg(gc->parent, "line %d: IRQ on %s edge\n",
 			offset,
 			rising ? "RISING" : "FALLING");
 	} else {
@@ -191,7 +192,7 @@
 		gpioibe &= ~bit;
 		gpioiev &= ~bit;
 		irq_set_handler_locked(d, handle_bad_irq);
-		dev_warn(gc->dev, "no trigger selected for line %d\n",
+		dev_warn(gc->parent, "no trigger selected for line %d\n",
 			 offset);
 	}
 
@@ -209,7 +210,7 @@
 	unsigned long pending;
 	int offset;
 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
-	struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+	struct pl061_gpio *chip = gpiochip_get_data(gc);
 	struct irq_chip *irqchip = irq_desc_get_chip(desc);
 
 	chained_irq_enter(irqchip, desc);
@@ -227,7 +228,7 @@
 static void pl061_irq_mask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+	struct pl061_gpio *chip = gpiochip_get_data(gc);
 	u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
 	u8 gpioie;
 
@@ -240,7 +241,7 @@
 static void pl061_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+	struct pl061_gpio *chip = gpiochip_get_data(gc);
 	u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
 	u8 gpioie;
 
@@ -261,7 +262,7 @@
 static void pl061_irq_ack(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+	struct pl061_gpio *chip = gpiochip_get_data(gc);
 	u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
 
 	spin_lock(&chip->lock);
@@ -269,12 +270,20 @@
 	spin_unlock(&chip->lock);
 }
 
+static int pl061_irq_set_wake(struct irq_data *d, unsigned int state)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+	return irq_set_irq_wake(gc->irq_parent, state);
+}
+
 static struct irq_chip pl061_irqchip = {
 	.name		= "pl061",
 	.irq_ack	= pl061_irq_ack,
 	.irq_mask	= pl061_irq_mask,
 	.irq_unmask	= pl061_irq_unmask,
 	.irq_set_type	= pl061_irq_type,
+	.irq_set_wake	= pl061_irq_set_wake,
 };
 
 static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
@@ -316,10 +325,10 @@
 	chip->gc.set = pl061_set_value;
 	chip->gc.ngpio = PL061_GPIO_NR;
 	chip->gc.label = dev_name(dev);
-	chip->gc.dev = dev;
+	chip->gc.parent = dev;
 	chip->gc.owner = THIS_MODULE;
 
-	ret = gpiochip_add(&chip->gc);
+	ret = gpiochip_add_data(&chip->gc, chip);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index df2ce55..b2b7b78 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -24,6 +24,7 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/syscore_ops.h>
 #include <linux/slab.h>
@@ -64,20 +65,11 @@
 int pxa_last_gpio;
 static int irq_base;
 
-#ifdef CONFIG_OF
-static struct irq_domain *domain;
-static struct device_node *pxa_gpio_of_node;
-#endif
-
-struct pxa_gpio_chip {
-	struct gpio_chip chip;
+struct pxa_gpio_bank {
 	void __iomem	*regbase;
-	char label[10];
-
 	unsigned long	irq_mask;
 	unsigned long	irq_edge_rise;
 	unsigned long	irq_edge_fall;
-	int (*set_wake)(unsigned int gpio, unsigned int on);
 
 #ifdef CONFIG_PM
 	unsigned long	saved_gplr;
@@ -87,6 +79,17 @@
 #endif
 };
 
+struct pxa_gpio_chip {
+	struct device *dev;
+	struct gpio_chip chip;
+	struct pxa_gpio_bank *banks;
+	struct irq_domain *irqdomain;
+
+	int irq0;
+	int irq1;
+	int (*set_wake)(unsigned int gpio, unsigned int on);
+};
+
 enum pxa_gpio_type {
 	PXA25X_GPIO = 0,
 	PXA26X_GPIO,
@@ -104,9 +107,8 @@
 };
 
 static DEFINE_SPINLOCK(gpio_lock);
-static struct pxa_gpio_chip *pxa_gpio_chips;
+static struct pxa_gpio_chip *pxa_gpio_chip;
 static enum pxa_gpio_type gpio_type;
-static void __iomem *gpio_reg_base;
 
 static struct pxa_gpio_id pxa25x_id = {
 	.type		= PXA25X_GPIO,
@@ -148,17 +150,28 @@
 	.gpio_nums	= 224,
 };
 
-#define for_each_gpio_chip(i, c)			\
-	for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++)
+#define for_each_gpio_bank(i, b, pc)					\
+	for (i = 0, b = pc->banks; i <= pxa_last_gpio; i += 32, b++)
 
-static inline void __iomem *gpio_chip_base(struct gpio_chip *c)
+static inline struct pxa_gpio_chip *chip_to_pxachip(struct gpio_chip *c)
 {
-	return container_of(c, struct pxa_gpio_chip, chip)->regbase;
+	struct pxa_gpio_chip *pxa_chip = gpiochip_get_data(c);
+
+	return pxa_chip;
 }
 
-static inline struct pxa_gpio_chip *gpio_to_pxachip(unsigned gpio)
+static inline void __iomem *gpio_bank_base(struct gpio_chip *c, int gpio)
 {
-	return &pxa_gpio_chips[gpio_to_bank(gpio)];
+	struct pxa_gpio_chip *p = gpiochip_get_data(c);
+	struct pxa_gpio_bank *bank = p->banks + (gpio / 32);
+
+	return bank->regbase;
+}
+
+static inline struct pxa_gpio_bank *gpio_to_pxabank(struct gpio_chip *c,
+						    unsigned gpio)
+{
+	return chip_to_pxachip(c)->banks + gpio / 32;
 }
 
 static inline int gpio_is_pxa_type(int type)
@@ -187,15 +200,13 @@
  * is attributed as "occupied" here (I know this terminology isn't
  * accurate, you are welcome to propose a better one :-)
  */
-static inline int __gpio_is_occupied(unsigned gpio)
+static inline int __gpio_is_occupied(struct pxa_gpio_chip *pchip, unsigned gpio)
 {
-	struct pxa_gpio_chip *pxachip;
 	void __iomem *base;
 	unsigned long gafr = 0, gpdr = 0;
 	int ret, af = 0, dir = 0;
 
-	pxachip = gpio_to_pxachip(gpio);
-	base = gpio_chip_base(&pxachip->chip);
+	base = gpio_bank_base(&pchip->chip, gpio);
 	gpdr = readl_relaxed(base + GPDR_OFFSET);
 
 	switch (gpio_type) {
@@ -218,21 +229,35 @@
 	return ret;
 }
 
-static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-	return chip->base + offset + irq_base;
-}
-
 int pxa_irq_to_gpio(int irq)
 {
-	return irq - irq_base;
+	struct pxa_gpio_chip *pchip = pxa_gpio_chip;
+	int irq_gpio0;
+
+	irq_gpio0 = irq_find_mapping(pchip->irqdomain, 0);
+	if (irq_gpio0 > 0)
+		return irq - irq_gpio0;
+
+	return irq_gpio0;
+}
+
+static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct pxa_gpio_chip *pchip = chip_to_pxachip(chip);
+
+	return irq_find_mapping(pchip->irqdomain, offset);
 }
 
 static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	void __iomem *base = gpio_chip_base(chip);
-	uint32_t value, mask = 1 << offset;
+	void __iomem *base = gpio_bank_base(chip, offset);
+	uint32_t value, mask = GPIO_bit(offset);
 	unsigned long flags;
+	int ret;
+
+	ret = pinctrl_gpio_direction_input(chip->base + offset);
+	if (!ret)
+		return 0;
 
 	spin_lock_irqsave(&gpio_lock, flags);
 
@@ -250,12 +275,17 @@
 static int pxa_gpio_direction_output(struct gpio_chip *chip,
 				     unsigned offset, int value)
 {
-	void __iomem *base = gpio_chip_base(chip);
-	uint32_t tmp, mask = 1 << offset;
+	void __iomem *base = gpio_bank_base(chip, offset);
+	uint32_t tmp, mask = GPIO_bit(offset);
 	unsigned long flags;
+	int ret;
 
 	writel_relaxed(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET));
 
+	ret = pinctrl_gpio_direction_output(chip->base + offset);
+	if (!ret)
+		return 0;
+
 	spin_lock_irqsave(&gpio_lock, flags);
 
 	tmp = readl_relaxed(base + GPDR_OFFSET);
@@ -271,14 +301,18 @@
 
 static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	u32 gplr = readl_relaxed(gpio_chip_base(chip) + GPLR_OFFSET);
-	return !!(gplr & (1 << offset));
+	void __iomem *base = gpio_bank_base(chip, offset);
+	u32 gplr = readl_relaxed(base + GPLR_OFFSET);
+
+	return !!(gplr & GPIO_bit(offset));
 }
 
 static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	writel_relaxed(1 << offset, gpio_chip_base(chip) +
-				(value ? GPSR_OFFSET : GPCR_OFFSET));
+	void __iomem *base = gpio_bank_base(chip, offset);
+
+	writel_relaxed(GPIO_bit(offset),
+		       base + (value ? GPSR_OFFSET : GPCR_OFFSET));
 }
 
 #ifdef CONFIG_OF_GPIO
@@ -289,61 +323,61 @@
 	if (gpiospec->args[0] > pxa_last_gpio)
 		return -EINVAL;
 
-	if (gc != &pxa_gpio_chips[gpiospec->args[0] / 32].chip)
-		return -EINVAL;
-
 	if (flags)
 		*flags = gpiospec->args[1];
 
-	return gpiospec->args[0] % 32;
+	return gpiospec->args[0];
 }
 #endif
 
-static int pxa_init_gpio_chip(int gpio_end,
-					int (*set_wake)(unsigned int, unsigned int))
+static int pxa_gpio_request(struct gpio_chip *chip, unsigned int offset)
 {
-	int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1;
-	struct pxa_gpio_chip *chips;
+	return pinctrl_request_gpio(chip->base + offset);
+}
 
-	chips = kzalloc(nbanks * sizeof(struct pxa_gpio_chip), GFP_KERNEL);
-	if (chips == NULL) {
-		pr_err("%s: failed to allocate GPIO chips\n", __func__);
+static void pxa_gpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+	pinctrl_free_gpio(chip->base + offset);
+}
+
+static int pxa_init_gpio_chip(struct pxa_gpio_chip *pchip, int ngpio,
+			      struct device_node *np, void __iomem *regbase)
+{
+	int i, gpio, nbanks = DIV_ROUND_UP(ngpio, 32);
+	struct pxa_gpio_bank *bank;
+
+	pchip->banks = devm_kcalloc(pchip->dev, nbanks, sizeof(*pchip->banks),
+				    GFP_KERNEL);
+	if (!pchip->banks)
 		return -ENOMEM;
-	}
 
-	for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) {
-		struct gpio_chip *c = &chips[i].chip;
-
-		sprintf(chips[i].label, "gpio-%d", i);
-		chips[i].regbase = gpio_reg_base + BANK_OFF(i);
-		chips[i].set_wake = set_wake;
-
-		c->base  = gpio;
-		c->label = chips[i].label;
-
-		c->direction_input  = pxa_gpio_direction_input;
-		c->direction_output = pxa_gpio_direction_output;
-		c->get = pxa_gpio_get;
-		c->set = pxa_gpio_set;
-		c->to_irq = pxa_gpio_to_irq;
+	pchip->chip.label = "gpio-pxa";
+	pchip->chip.direction_input  = pxa_gpio_direction_input;
+	pchip->chip.direction_output = pxa_gpio_direction_output;
+	pchip->chip.get = pxa_gpio_get;
+	pchip->chip.set = pxa_gpio_set;
+	pchip->chip.to_irq = pxa_gpio_to_irq;
+	pchip->chip.ngpio = ngpio;
+	pchip->chip.request = pxa_gpio_request;
+	pchip->chip.free = pxa_gpio_free;
 #ifdef CONFIG_OF_GPIO
-		c->of_node = pxa_gpio_of_node;
-		c->of_xlate = pxa_gpio_of_xlate;
-		c->of_gpio_n_cells = 2;
+	pchip->chip.of_node = np;
+	pchip->chip.of_xlate = pxa_gpio_of_xlate;
+	pchip->chip.of_gpio_n_cells = 2;
 #endif
 
-		/* number of GPIOs on last bank may be less than 32 */
-		c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32;
-		gpiochip_add(c);
+	for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) {
+		bank = pchip->banks + i;
+		bank->regbase = regbase + BANK_OFF(i);
 	}
-	pxa_gpio_chips = chips;
-	return 0;
+
+	return gpiochip_add_data(&pchip->chip, pchip);
 }
 
 /* Update only those GRERx and GFERx edge detection register bits if those
  * bits are set in c->irq_mask
  */
-static inline void update_edge_detect(struct pxa_gpio_chip *c)
+static inline void update_edge_detect(struct pxa_gpio_bank *c)
 {
 	uint32_t grer, gfer;
 
@@ -357,12 +391,11 @@
 
 static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
 {
-	struct pxa_gpio_chip *c;
-	int gpio = pxa_irq_to_gpio(d->irq);
+	struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
+	unsigned int gpio = irqd_to_hwirq(d);
+	struct pxa_gpio_bank *c = gpio_to_pxabank(&pchip->chip, gpio);
 	unsigned long gpdr, mask = GPIO_bit(gpio);
 
-	c = gpio_to_pxachip(gpio);
-
 	if (type == IRQ_TYPE_PROBE) {
 		/* Don't mess with enabled GPIOs using preconfigured edges or
 		 * GPIOs set to alternate function or to output during probe
@@ -370,7 +403,7 @@
 		if ((c->irq_edge_rise | c->irq_edge_fall) & GPIO_bit(gpio))
 			return 0;
 
-		if (__gpio_is_occupied(gpio))
+		if (__gpio_is_occupied(pchip, gpio))
 			return 0;
 
 		type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
@@ -401,20 +434,16 @@
 	return 0;
 }
 
-static void pxa_gpio_demux_handler(struct irq_desc *desc)
+static irqreturn_t pxa_gpio_demux_handler(int in_irq, void *d)
 {
-	struct pxa_gpio_chip *c;
-	int loop, gpio, gpio_base, n;
+	int loop, gpio, n, handled = 0;
 	unsigned long gedr;
-	struct irq_chip *chip = irq_desc_get_chip(desc);
-
-	chained_irq_enter(chip, desc);
+	struct pxa_gpio_chip *pchip = d;
+	struct pxa_gpio_bank *c;
 
 	do {
 		loop = 0;
-		for_each_gpio_chip(gpio, c) {
-			gpio_base = c->chip.base;
-
+		for_each_gpio_bank(gpio, c, pchip) {
 			gedr = readl_relaxed(c->regbase + GEDR_OFFSET);
 			gedr = gedr & c->irq_mask;
 			writel_relaxed(gedr, c->regbase + GEDR_OFFSET);
@@ -422,51 +451,71 @@
 			for_each_set_bit(n, &gedr, BITS_PER_LONG) {
 				loop = 1;
 
-				generic_handle_irq(gpio_to_irq(gpio_base + n));
+				generic_handle_irq(gpio_to_irq(gpio + n));
 			}
 		}
+		handled += loop;
 	} while (loop);
 
-	chained_irq_exit(chip, desc);
+	return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static irqreturn_t pxa_gpio_direct_handler(int in_irq, void *d)
+{
+	struct pxa_gpio_chip *pchip = d;
+
+	if (in_irq == pchip->irq0) {
+		generic_handle_irq(gpio_to_irq(0));
+	} else if (in_irq == pchip->irq1) {
+		generic_handle_irq(gpio_to_irq(1));
+	} else {
+		pr_err("%s() unknown irq %d\n", __func__, in_irq);
+		return IRQ_NONE;
+	}
+	return IRQ_HANDLED;
 }
 
 static void pxa_ack_muxed_gpio(struct irq_data *d)
 {
-	int gpio = pxa_irq_to_gpio(d->irq);
-	struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
+	struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
+	unsigned int gpio = irqd_to_hwirq(d);
+	void __iomem *base = gpio_bank_base(&pchip->chip, gpio);
 
-	writel_relaxed(GPIO_bit(gpio), c->regbase + GEDR_OFFSET);
+	writel_relaxed(GPIO_bit(gpio), base + GEDR_OFFSET);
 }
 
 static void pxa_mask_muxed_gpio(struct irq_data *d)
 {
-	int gpio = pxa_irq_to_gpio(d->irq);
-	struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
+	struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
+	unsigned int gpio = irqd_to_hwirq(d);
+	struct pxa_gpio_bank *b = gpio_to_pxabank(&pchip->chip, gpio);
+	void __iomem *base = gpio_bank_base(&pchip->chip, gpio);
 	uint32_t grer, gfer;
 
-	c->irq_mask &= ~GPIO_bit(gpio);
+	b->irq_mask &= ~GPIO_bit(gpio);
 
-	grer = readl_relaxed(c->regbase + GRER_OFFSET) & ~GPIO_bit(gpio);
-	gfer = readl_relaxed(c->regbase + GFER_OFFSET) & ~GPIO_bit(gpio);
-	writel_relaxed(grer, c->regbase + GRER_OFFSET);
-	writel_relaxed(gfer, c->regbase + GFER_OFFSET);
+	grer = readl_relaxed(base + GRER_OFFSET) & ~GPIO_bit(gpio);
+	gfer = readl_relaxed(base + GFER_OFFSET) & ~GPIO_bit(gpio);
+	writel_relaxed(grer, base + GRER_OFFSET);
+	writel_relaxed(gfer, base + GFER_OFFSET);
 }
 
 static int pxa_gpio_set_wake(struct irq_data *d, unsigned int on)
 {
-	int gpio = pxa_irq_to_gpio(d->irq);
-	struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
+	struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
+	unsigned int gpio = irqd_to_hwirq(d);
 
-	if (c->set_wake)
-		return c->set_wake(gpio, on);
+	if (pchip->set_wake)
+		return pchip->set_wake(gpio, on);
 	else
 		return 0;
 }
 
 static void pxa_unmask_muxed_gpio(struct irq_data *d)
 {
-	int gpio = pxa_irq_to_gpio(d->irq);
-	struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
+	struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
+	unsigned int gpio = irqd_to_hwirq(d);
+	struct pxa_gpio_bank *c = gpio_to_pxabank(&pchip->chip, gpio);
 
 	c->irq_mask |= GPIO_bit(gpio);
 	update_edge_detect(c);
@@ -506,6 +555,21 @@
 	return count;
 }
 
+static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq,
+			      irq_hw_number_t hw)
+{
+	irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+				 handle_edge_irq);
+	irq_set_chip_data(irq, d->host_data);
+	irq_set_noprobe(irq);
+	return 0;
+}
+
+const struct irq_domain_ops pxa_irq_domain_ops = {
+	.map	= pxa_irq_domain_map,
+	.xlate	= irq_domain_xlate_twocell,
+};
+
 #ifdef CONFIG_OF
 static const struct of_device_id pxa_gpio_dt_ids[] = {
 	{ .compatible = "intel,pxa25x-gpio",	.data = &pxa25x_id, },
@@ -519,24 +583,10 @@
 	{}
 };
 
-static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq,
-			      irq_hw_number_t hw)
+static int pxa_gpio_probe_dt(struct platform_device *pdev,
+			     struct pxa_gpio_chip *pchip)
 {
-	irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
-				 handle_edge_irq);
-	irq_set_noprobe(irq);
-	return 0;
-}
-
-const struct irq_domain_ops pxa_irq_domain_ops = {
-	.map	= pxa_irq_domain_map,
-	.xlate	= irq_domain_xlate_twocell,
-};
-
-static int pxa_gpio_probe_dt(struct platform_device *pdev)
-{
-	int ret = 0, nr_gpios;
-	struct device_node *np = pdev->dev.of_node;
+	int nr_gpios;
 	const struct of_device_id *of_id =
 				of_match_device(pxa_gpio_dt_ids, &pdev->dev);
 	const struct pxa_gpio_id *gpio_id;
@@ -554,57 +604,64 @@
 	irq_base = irq_alloc_descs(-1, 0, nr_gpios, 0);
 	if (irq_base < 0) {
 		dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
-		ret = irq_base;
-		goto err;
+		return irq_base;
 	}
-	domain = irq_domain_add_legacy(np, nr_gpios, irq_base, 0,
-				       &pxa_irq_domain_ops, NULL);
-	pxa_gpio_of_node = np;
-	return 0;
-err:
-	iounmap(gpio_reg_base);
-	return ret;
+	return irq_base;
 }
 #else
-#define pxa_gpio_probe_dt(pdev)		(-1)
+#define pxa_gpio_probe_dt(pdev, pchip)		(-1)
 #endif
 
 static int pxa_gpio_probe(struct platform_device *pdev)
 {
-	struct pxa_gpio_chip *c;
+	struct pxa_gpio_chip *pchip;
+	struct pxa_gpio_bank *c;
 	struct resource *res;
 	struct clk *clk;
 	struct pxa_gpio_platform_data *info;
-	int gpio, irq, ret, use_of = 0;
+	void __iomem *gpio_reg_base;
+	int gpio, ret;
 	int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0;
 
+	pchip = devm_kzalloc(&pdev->dev, sizeof(*pchip), GFP_KERNEL);
+	if (!pchip)
+		return -ENOMEM;
+	pchip->dev = &pdev->dev;
+
 	info = dev_get_platdata(&pdev->dev);
 	if (info) {
 		irq_base = info->irq_base;
 		if (irq_base <= 0)
 			return -EINVAL;
 		pxa_last_gpio = pxa_gpio_nums(pdev);
+		pchip->set_wake = info->gpio_set_wake;
 	} else {
-		irq_base = 0;
-		use_of = 1;
-		ret = pxa_gpio_probe_dt(pdev);
-		if (ret < 0)
+		irq_base = pxa_gpio_probe_dt(pdev, pchip);
+		if (irq_base < 0)
 			return -EINVAL;
 	}
 
 	if (!pxa_last_gpio)
 		return -EINVAL;
 
+	pchip->irqdomain = irq_domain_add_legacy(pdev->dev.of_node,
+						 pxa_last_gpio + 1, irq_base,
+						 0, &pxa_irq_domain_ops, pchip);
+	if (!pchip->irqdomain)
+		return -ENOMEM;
+
 	irq0 = platform_get_irq_byname(pdev, "gpio0");
 	irq1 = platform_get_irq_byname(pdev, "gpio1");
 	irq_mux = platform_get_irq_byname(pdev, "gpio_mux");
 	if ((irq0 > 0 && irq1 <= 0) || (irq0 <= 0 && irq1 > 0)
 		|| (irq_mux <= 0))
 		return -EINVAL;
+
+	pchip->irq0 = irq0;
+	pchip->irq1 = irq1;
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -EINVAL;
-	gpio_reg_base = ioremap(res->start, resource_size(res));
+	gpio_reg_base = devm_ioremap(&pdev->dev, res->start,
+				     resource_size(res));
 	if (!gpio_reg_base)
 		return -EINVAL;
 
@@ -615,21 +672,24 @@
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "Error %ld to get gpio clock\n",
 			PTR_ERR(clk));
-		iounmap(gpio_reg_base);
 		return PTR_ERR(clk);
 	}
 	ret = clk_prepare_enable(clk);
 	if (ret) {
 		clk_put(clk);
-		iounmap(gpio_reg_base);
 		return ret;
 	}
 
 	/* Initialize GPIO chips */
-	pxa_init_gpio_chip(pxa_last_gpio, info ? info->gpio_set_wake : NULL);
+	ret = pxa_init_gpio_chip(pchip, pxa_last_gpio + 1, pdev->dev.of_node,
+				 gpio_reg_base);
+	if (ret) {
+		clk_put(clk);
+		return ret;
+	}
 
 	/* clear all GPIO edge detects */
-	for_each_gpio_chip(gpio, c) {
+	for_each_gpio_bank(gpio, c, pchip) {
 		writel_relaxed(0, c->regbase + GFER_OFFSET);
 		writel_relaxed(0, c->regbase + GRER_OFFSET);
 		writel_relaxed(~0, c->regbase + GEDR_OFFSET);
@@ -638,34 +698,31 @@
 			writel_relaxed(~0, c->regbase + ED_MASK_OFFSET);
 	}
 
-	if (!use_of) {
-		if (irq0 > 0) {
-			irq = gpio_to_irq(0);
-			irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
-						 handle_edge_irq);
-			irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
-		}
-		if (irq1 > 0) {
-			irq = gpio_to_irq(1);
-			irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
-						 handle_edge_irq);
-			irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
-		}
-
-		for (irq  = gpio_to_irq(gpio_offset);
-			irq <= gpio_to_irq(pxa_last_gpio); irq++) {
-			irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
-						 handle_edge_irq);
-			irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
-		}
+	if (irq0 > 0) {
+		ret = devm_request_irq(&pdev->dev,
+				       irq0, pxa_gpio_direct_handler, 0,
+				       "gpio-0", pchip);
+		if (ret)
+			dev_err(&pdev->dev, "request of gpio0 irq failed: %d\n",
+				ret);
 	}
+	if (irq1 > 0) {
+		ret = devm_request_irq(&pdev->dev,
+				       irq1, pxa_gpio_direct_handler, 0,
+				       "gpio-1", pchip);
+		if (ret)
+			dev_err(&pdev->dev, "request of gpio1 irq failed: %d\n",
+				ret);
+	}
+	ret = devm_request_irq(&pdev->dev,
+			       irq_mux, pxa_gpio_demux_handler, 0,
+				       "gpio-mux", pchip);
+	if (ret)
+		dev_err(&pdev->dev, "request of gpio-mux irq failed: %d\n",
+				ret);
 
-	if (irq0 > 0)
-		irq_set_chained_handler(irq0, pxa_gpio_demux_handler);
-	if (irq1 > 0)
-		irq_set_chained_handler(irq1, pxa_gpio_demux_handler);
+	pxa_gpio_chip = pchip;
 
-	irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler);
 	return 0;
 }
 
@@ -690,19 +747,32 @@
 	.id_table	= gpio_id_table,
 };
 
-static int __init pxa_gpio_init(void)
+static int __init pxa_gpio_legacy_init(void)
 {
+	if (of_have_populated_dt())
+		return 0;
+
 	return platform_driver_register(&pxa_gpio_driver);
 }
-postcore_initcall(pxa_gpio_init);
+postcore_initcall(pxa_gpio_legacy_init);
+
+static int __init pxa_gpio_dt_init(void)
+{
+	if (of_have_populated_dt())
+		return platform_driver_register(&pxa_gpio_driver);
+
+	return 0;
+}
+device_initcall(pxa_gpio_dt_init);
 
 #ifdef CONFIG_PM
 static int pxa_gpio_suspend(void)
 {
-	struct pxa_gpio_chip *c;
+	struct pxa_gpio_chip *pchip = pxa_gpio_chip;
+	struct pxa_gpio_bank *c;
 	int gpio;
 
-	for_each_gpio_chip(gpio, c) {
+	for_each_gpio_bank(gpio, c, pchip) {
 		c->saved_gplr = readl_relaxed(c->regbase + GPLR_OFFSET);
 		c->saved_gpdr = readl_relaxed(c->regbase + GPDR_OFFSET);
 		c->saved_grer = readl_relaxed(c->regbase + GRER_OFFSET);
@@ -716,10 +786,11 @@
 
 static void pxa_gpio_resume(void)
 {
-	struct pxa_gpio_chip *c;
+	struct pxa_gpio_chip *pchip = pxa_gpio_chip;
+	struct pxa_gpio_bank *c;
 	int gpio;
 
-	for_each_gpio_chip(gpio, c) {
+	for_each_gpio_bank(gpio, c, pchip) {
 		/* restore level with set/clear */
 		writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET);
 		writel_relaxed(~c->saved_gplr, c->regbase + GPCR_OFFSET);
diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c
index 6eabf23..1e2d210 100644
--- a/drivers/gpio/gpio-rc5t583.c
+++ b/drivers/gpio/gpio-rc5t583.c
@@ -34,14 +34,9 @@
 	struct rc5t583 *rc5t583;
 };
 
-static inline struct rc5t583_gpio *to_rc5t583_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct rc5t583_gpio, gpio_chip);
-}
-
 static int rc5t583_gpio_get(struct gpio_chip *gc, unsigned int offset)
 {
-	struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+	struct rc5t583_gpio *rc5t583_gpio = gpiochip_get_data(gc);
 	struct device *parent = rc5t583_gpio->rc5t583->dev;
 	uint8_t val = 0;
 	int ret;
@@ -55,7 +50,7 @@
 
 static void rc5t583_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
 {
-	struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+	struct rc5t583_gpio *rc5t583_gpio = gpiochip_get_data(gc);
 	struct device *parent = rc5t583_gpio->rc5t583->dev;
 	if (val)
 		rc5t583_set_bits(parent, RC5T583_GPIO_IOOUT, BIT(offset));
@@ -65,7 +60,7 @@
 
 static int rc5t583_gpio_dir_input(struct gpio_chip *gc, unsigned int offset)
 {
-	struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+	struct rc5t583_gpio *rc5t583_gpio = gpiochip_get_data(gc);
 	struct device *parent = rc5t583_gpio->rc5t583->dev;
 	int ret;
 
@@ -80,7 +75,7 @@
 static int rc5t583_gpio_dir_output(struct gpio_chip *gc, unsigned offset,
 			int value)
 {
-	struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+	struct rc5t583_gpio *rc5t583_gpio = gpiochip_get_data(gc);
 	struct device *parent = rc5t583_gpio->rc5t583->dev;
 	int ret;
 
@@ -95,7 +90,7 @@
 
 static int rc5t583_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 {
-	struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+	struct rc5t583_gpio *rc5t583_gpio = gpiochip_get_data(gc);
 
 	if (offset < RC5T583_MAX_GPIO)
 		return rc5t583_gpio->rc5t583->irq_base +
@@ -105,7 +100,7 @@
 
 static void rc5t583_gpio_free(struct gpio_chip *gc, unsigned offset)
 {
-	struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+	struct rc5t583_gpio *rc5t583_gpio = gpiochip_get_data(gc);
 	struct device *parent = rc5t583_gpio->rc5t583->dev;
 
 	rc5t583_set_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset));
@@ -132,7 +127,7 @@
 	rc5t583_gpio->gpio_chip.to_irq = rc5t583_gpio_to_irq,
 	rc5t583_gpio->gpio_chip.ngpio = RC5T583_MAX_GPIO,
 	rc5t583_gpio->gpio_chip.can_sleep = true,
-	rc5t583_gpio->gpio_chip.dev = &pdev->dev;
+	rc5t583_gpio->gpio_chip.parent = &pdev->dev;
 	rc5t583_gpio->gpio_chip.base = -1;
 	rc5t583_gpio->rc5t583 = rc5t583;
 
@@ -141,7 +136,7 @@
 
 	platform_set_drvdata(pdev, rc5t583_gpio);
 
-	return gpiochip_add(&rc5t583_gpio->gpio_chip);
+	return gpiochip_add_data(&rc5t583_gpio->gpio_chip, rc5t583_gpio);
 }
 
 static int rc5t583_gpio_remove(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 2a81224..cf41440 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -25,7 +25,6 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/pinctrl/consumer.h>
-#include <linux/platform_data/gpio-rcar.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/spinlock.h>
@@ -34,12 +33,13 @@
 struct gpio_rcar_priv {
 	void __iomem *base;
 	spinlock_t lock;
-	struct gpio_rcar_config config;
 	struct platform_device *pdev;
 	struct gpio_chip gpio_chip;
 	struct irq_chip irq_chip;
-	unsigned int irq_parent;
 	struct clk *clk;
+	unsigned int irq_parent;
+	bool has_both_edge_trigger;
+	bool needs_clk;
 };
 
 #define IOINTSEL 0x00	/* General IO/Interrupt Switching Register */
@@ -84,8 +84,7 @@
 static void gpio_rcar_irq_disable(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
-						gpio_chip);
+	struct gpio_rcar_priv *p = gpiochip_get_data(gc);
 
 	gpio_rcar_write(p, INTMSK, ~BIT(irqd_to_hwirq(d)));
 }
@@ -93,8 +92,7 @@
 static void gpio_rcar_irq_enable(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
-						gpio_chip);
+	struct gpio_rcar_priv *p = gpiochip_get_data(gc);
 
 	gpio_rcar_write(p, MSKCLR, BIT(irqd_to_hwirq(d)));
 }
@@ -121,7 +119,7 @@
 	gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger);
 
 	/* Select one edge or both edges in BOTHEDGE */
-	if (p->config.has_both_edge_trigger)
+	if (p->has_both_edge_trigger)
 		gpio_rcar_modify_bit(p, BOTHEDGE, hwirq, both);
 
 	/* Select "Interrupt Input Mode" in IOINTSEL */
@@ -137,8 +135,7 @@
 static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
-						gpio_chip);
+	struct gpio_rcar_priv *p = gpiochip_get_data(gc);
 	unsigned int hwirq = irqd_to_hwirq(d);
 
 	dev_dbg(&p->pdev->dev, "sense irq = %d, type = %d\n", hwirq, type);
@@ -161,7 +158,7 @@
 						      false);
 		break;
 	case IRQ_TYPE_EDGE_BOTH:
-		if (!p->config.has_both_edge_trigger)
+		if (!p->has_both_edge_trigger)
 			return -EINVAL;
 		gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false,
 						      true);
@@ -175,8 +172,7 @@
 static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
-						gpio_chip);
+	struct gpio_rcar_priv *p = gpiochip_get_data(gc);
 	int error;
 
 	if (p->irq_parent) {
@@ -218,16 +214,11 @@
 	return irqs_handled ? IRQ_HANDLED : IRQ_NONE;
 }
 
-static inline struct gpio_rcar_priv *gpio_to_priv(struct gpio_chip *chip)
-{
-	return container_of(chip, struct gpio_rcar_priv, gpio_chip);
-}
-
 static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
 						       unsigned int gpio,
 						       bool output)
 {
-	struct gpio_rcar_priv *p = gpio_to_priv(chip);
+	struct gpio_rcar_priv *p = gpiochip_get_data(chip);
 	unsigned long flags;
 
 	/* follow steps in the GPIO documentation for
@@ -251,7 +242,7 @@
 
 static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset)
 {
-	struct gpio_rcar_priv *p = gpio_to_priv(chip);
+	struct gpio_rcar_priv *p = gpiochip_get_data(chip);
 	int error;
 
 	error = pm_runtime_get_sync(&p->pdev->dev);
@@ -267,7 +258,7 @@
 
 static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset)
 {
-	struct gpio_rcar_priv *p = gpio_to_priv(chip);
+	struct gpio_rcar_priv *p = gpiochip_get_data(chip);
 
 	pinctrl_free_gpio(chip->base + offset);
 
@@ -291,15 +282,15 @@
 
 	/* testing on r8a7790 shows that INDT does not show correct pin state
 	 * when configured as output, so use OUTDT in case of output pins */
-	if (gpio_rcar_read(gpio_to_priv(chip), INOUTSEL) & bit)
-		return !!(gpio_rcar_read(gpio_to_priv(chip), OUTDT) & bit);
+	if (gpio_rcar_read(gpiochip_get_data(chip), INOUTSEL) & bit)
+		return !!(gpio_rcar_read(gpiochip_get_data(chip), OUTDT) & bit);
 	else
-		return !!(gpio_rcar_read(gpio_to_priv(chip), INDT) & bit);
+		return !!(gpio_rcar_read(gpiochip_get_data(chip), INDT) & bit);
 }
 
 static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct gpio_rcar_priv *p = gpio_to_priv(chip);
+	struct gpio_rcar_priv *p = gpiochip_get_data(chip);
 	unsigned long flags;
 
 	spin_lock_irqsave(&p->lock, flags);
@@ -318,14 +309,17 @@
 
 struct gpio_rcar_info {
 	bool has_both_edge_trigger;
+	bool needs_clk;
 };
 
 static const struct gpio_rcar_info gpio_rcar_info_gen1 = {
 	.has_both_edge_trigger = false,
+	.needs_clk = false,
 };
 
 static const struct gpio_rcar_info gpio_rcar_info_gen2 = {
 	.has_both_edge_trigger = true,
+	.needs_clk = true,
 };
 
 static const struct of_device_id gpio_rcar_of_table[] = {
@@ -355,39 +349,30 @@
 
 MODULE_DEVICE_TABLE(of, gpio_rcar_of_table);
 
-static int gpio_rcar_parse_pdata(struct gpio_rcar_priv *p)
+static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
 {
-	struct gpio_rcar_config *pdata = dev_get_platdata(&p->pdev->dev);
 	struct device_node *np = p->pdev->dev.of_node;
+	const struct of_device_id *match;
+	const struct gpio_rcar_info *info;
 	struct of_phandle_args args;
 	int ret;
 
-	if (pdata) {
-		p->config = *pdata;
-	} else if (IS_ENABLED(CONFIG_OF) && np) {
-		const struct of_device_id *match;
-		const struct gpio_rcar_info *info;
+	match = of_match_node(gpio_rcar_of_table, np);
+	if (!match)
+		return -EINVAL;
 
-		match = of_match_node(gpio_rcar_of_table, np);
-		if (!match)
-			return -EINVAL;
+	info = match->data;
 
-		info = match->data;
+	ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);
+	*npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
+	p->has_both_edge_trigger = info->has_both_edge_trigger;
+	p->needs_clk = info->needs_clk;
 
-		ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0,
-						       &args);
-		p->config.number_of_pins = ret == 0 ? args.args[2]
-					 : RCAR_MAX_GPIO_PER_BANK;
-		p->config.gpio_base = -1;
-		p->config.has_both_edge_trigger = info->has_both_edge_trigger;
-	}
-
-	if (p->config.number_of_pins == 0 ||
-	    p->config.number_of_pins > RCAR_MAX_GPIO_PER_BANK) {
+	if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) {
 		dev_warn(&p->pdev->dev,
-			 "Invalid number of gpio lines %u, using %u\n",
-			 p->config.number_of_pins, RCAR_MAX_GPIO_PER_BANK);
-		p->config.number_of_pins = RCAR_MAX_GPIO_PER_BANK;
+			 "Invalid number of gpio lines %u, using %u\n", *npins,
+			 RCAR_MAX_GPIO_PER_BANK);
+		*npins = RCAR_MAX_GPIO_PER_BANK;
 	}
 
 	return 0;
@@ -401,6 +386,7 @@
 	struct irq_chip *irq_chip;
 	struct device *dev = &pdev->dev;
 	const char *name = dev_name(dev);
+	unsigned int npins;
 	int ret;
 
 	p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
@@ -410,8 +396,8 @@
 	p->pdev = pdev;
 	spin_lock_init(&p->lock);
 
-	/* Get device configuration from DT node or platform data. */
-	ret = gpio_rcar_parse_pdata(p);
+	/* Get device configuration from DT node */
+	ret = gpio_rcar_parse_dt(p, &npins);
 	if (ret < 0)
 		return ret;
 
@@ -419,7 +405,11 @@
 
 	p->clk = devm_clk_get(dev, NULL);
 	if (IS_ERR(p->clk)) {
-		dev_warn(dev, "unable to get clock\n");
+		if (p->needs_clk) {
+			dev_err(dev, "unable to get clock\n");
+			ret = PTR_ERR(p->clk);
+			goto err0;
+		}
 		p->clk = NULL;
 	}
 
@@ -449,10 +439,10 @@
 	gpio_chip->direction_output = gpio_rcar_direction_output;
 	gpio_chip->set = gpio_rcar_set;
 	gpio_chip->label = name;
-	gpio_chip->dev = dev;
+	gpio_chip->parent = dev;
 	gpio_chip->owner = THIS_MODULE;
-	gpio_chip->base = p->config.gpio_base;
-	gpio_chip->ngpio = p->config.number_of_pins;
+	gpio_chip->base = -1;
+	gpio_chip->ngpio = npins;
 
 	irq_chip = &p->irq_chip;
 	irq_chip->name = name;
@@ -462,14 +452,14 @@
 	irq_chip->irq_set_wake = gpio_rcar_irq_set_wake;
 	irq_chip->flags	= IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
 
-	ret = gpiochip_add(gpio_chip);
+	ret = gpiochip_add_data(gpio_chip, p);
 	if (ret) {
 		dev_err(dev, "failed to add GPIO controller\n");
 		goto err0;
 	}
 
-	ret = gpiochip_irqchip_add(gpio_chip, irq_chip, p->config.irq_base,
-				   handle_level_irq, IRQ_TYPE_NONE);
+	ret = gpiochip_irqchip_add(gpio_chip, irq_chip, 0, handle_level_irq,
+				   IRQ_TYPE_NONE);
 	if (ret) {
 		dev_err(dev, "cannot add irqchip\n");
 		goto err1;
@@ -483,22 +473,7 @@
 		goto err1;
 	}
 
-	dev_info(dev, "driving %d GPIOs\n", p->config.number_of_pins);
-
-	/* warn in case of mismatch if irq base is specified */
-	if (p->config.irq_base) {
-		ret = irq_find_mapping(gpio_chip->irqdomain, 0);
-		if (p->config.irq_base != ret)
-			dev_warn(dev, "irq base mismatch (%u/%u)\n",
-				 p->config.irq_base, ret);
-	}
-
-	if (p->config.pctl_name) {
-		ret = gpiochip_add_pin_range(gpio_chip, p->config.pctl_name, 0,
-					     gpio_chip->base, gpio_chip->ngpio);
-		if (ret < 0)
-			dev_warn(dev, "failed to add pin range\n");
-	}
+	dev_info(dev, "driving %d GPIOs\n", npins);
 
 	return 0;
 
diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c
index d729bc8..96ddee3 100644
--- a/drivers/gpio/gpio-rdc321x.c
+++ b/drivers/gpio/gpio-rdc321x.c
@@ -47,7 +47,7 @@
 	u32 value = 0;
 	int reg;
 
-	gpch = container_of(chip, struct rdc321x_gpio, chip);
+	gpch = gpiochip_get_data(chip);
 	reg = gpio < 32 ? gpch->reg1_data_base : gpch->reg2_data_base;
 
 	spin_lock(&gpch->lock);
@@ -65,7 +65,7 @@
 	struct rdc321x_gpio *gpch;
 	int reg = (gpio < 32) ? 0 : 1;
 
-	gpch = container_of(chip, struct rdc321x_gpio, chip);
+	gpch = gpiochip_get_data(chip);
 
 	if (value)
 		gpch->data_reg[reg] |= 1 << (gpio & 0x1f);
@@ -83,7 +83,7 @@
 {
 	struct rdc321x_gpio *gpch;
 
-	gpch = container_of(chip, struct rdc321x_gpio, chip);
+	gpch = gpiochip_get_data(chip);
 	spin_lock(&gpch->lock);
 	rdc_gpio_set_value_impl(chip, gpio, value);
 	spin_unlock(&gpch->lock);
@@ -96,7 +96,7 @@
 	int err;
 	u32 reg;
 
-	gpch = container_of(chip, struct rdc321x_gpio, chip);
+	gpch = gpiochip_get_data(chip);
 
 	spin_lock(&gpch->lock);
 	err = pci_read_config_dword(gpch->sb_pdev, gpio < 32 ?
@@ -194,7 +194,7 @@
 
 	dev_info(&pdev->dev, "registering %d GPIOs\n",
 					rdc321x_gpio_dev->chip.ngpio);
-	return gpiochip_add(&rdc321x_gpio_dev->chip);
+	return gpiochip_add_data(&rdc321x_gpio_dev->chip, rdc321x_gpio_dev);
 }
 
 static int rdc321x_gpio_remove(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c
index 990fa90..0c99e8f 100644
--- a/drivers/gpio/gpio-sa1100.c
+++ b/drivers/gpio/gpio-sa1100.c
@@ -17,7 +17,7 @@
 
 static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	return GPLR & GPIO_GPIO(offset);
+	return !!(GPLR & GPIO_GPIO(offset));
 }
 
 static void sa1100_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -238,7 +238,7 @@
 	GRER = 0;
 	GEDR = -1;
 
-	gpiochip_add(&sa1100_gpio_chip);
+	gpiochip_add_data(&sa1100_gpio_chip, NULL);
 
 	sa1100_gpio_irqdomain = irq_domain_add_simple(NULL,
 			28, IRQ_GPIO0,
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c
index 7c288ba..4cb4a31 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -753,7 +753,7 @@
 #endif
 
 	/* gpiochip_add() prints own failure message on error. */
-	ret = gpiochip_add(gc);
+	ret = gpiochip_add_data(gc, chip);
 	if (ret >= 0)
 		s3c_gpiolib_track(chip);
 }
@@ -862,7 +862,7 @@
 
 int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset)
 {
-	struct samsung_gpio_chip *samsung_chip = container_of(chip, struct samsung_gpio_chip, chip);
+	struct samsung_gpio_chip *samsung_chip = gpiochip_get_data(chip);
 
 	return samsung_chip->irq_base + offset;
 }
diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
index b72906f..5314ee4 100644
--- a/drivers/gpio/gpio-sch.c
+++ b/drivers/gpio/gpio-sch.c
@@ -41,8 +41,6 @@
 	unsigned short resume_base;
 };
 
-#define to_sch_gpio(gc)	container_of(gc, struct sch_gpio, chip)
-
 static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio,
 				unsigned reg)
 {
@@ -65,7 +63,7 @@
 
 static int sch_gpio_reg_get(struct gpio_chip *gc, unsigned gpio, unsigned reg)
 {
-	struct sch_gpio *sch = to_sch_gpio(gc);
+	struct sch_gpio *sch = gpiochip_get_data(gc);
 	unsigned short offset, bit;
 	u8 reg_val;
 
@@ -80,7 +78,7 @@
 static void sch_gpio_reg_set(struct gpio_chip *gc, unsigned gpio, unsigned reg,
 			     int val)
 {
-	struct sch_gpio *sch = to_sch_gpio(gc);
+	struct sch_gpio *sch = gpiochip_get_data(gc);
 	unsigned short offset, bit;
 	u8 reg_val;
 
@@ -97,7 +95,7 @@
 
 static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
 {
-	struct sch_gpio *sch = to_sch_gpio(gc);
+	struct sch_gpio *sch = gpiochip_get_data(gc);
 
 	spin_lock(&sch->lock);
 	sch_gpio_reg_set(gc, gpio_num, GIO, 1);
@@ -112,7 +110,7 @@
 
 static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
 {
-	struct sch_gpio *sch = to_sch_gpio(gc);
+	struct sch_gpio *sch = gpiochip_get_data(gc);
 
 	spin_lock(&sch->lock);
 	sch_gpio_reg_set(gc, gpio_num, GLV, val);
@@ -122,7 +120,7 @@
 static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,
 				  int val)
 {
-	struct sch_gpio *sch = to_sch_gpio(gc);
+	struct sch_gpio *sch = gpiochip_get_data(gc);
 
 	spin_lock(&sch->lock);
 	sch_gpio_reg_set(gc, gpio_num, GIO, 0);
@@ -171,7 +169,7 @@
 	sch->iobase = res->start;
 	sch->chip = sch_gpio_chip;
 	sch->chip.label = dev_name(&pdev->dev);
-	sch->chip.dev = &pdev->dev;
+	sch->chip.parent = &pdev->dev;
 
 	switch (pdev->id) {
 	case PCI_DEVICE_ID_INTEL_SCH_LPC:
@@ -217,7 +215,7 @@
 
 	platform_set_drvdata(pdev, sch);
 
-	return gpiochip_add(&sch->chip);
+	return gpiochip_add_data(&sch->chip, sch);
 }
 
 static int sch_gpio_remove(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c
index 0cb1141..1cbd77a 100644
--- a/drivers/gpio/gpio-sch311x.c
+++ b/drivers/gpio/gpio-sch311x.c
@@ -93,13 +93,6 @@
 	},
 };
 
-static inline struct sch311x_gpio_block *
-to_sch311x_gpio_block(struct gpio_chip *chip)
-{
-	return container_of(chip, struct sch311x_gpio_block, chip);
-}
-
-
 /*
  *	Super-IO functions
  */
@@ -142,14 +135,14 @@
 
 static int sch311x_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
-	struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+	struct sch311x_gpio_block *block = gpiochip_get_data(chip);
 
 	if (block->config_regs[offset] == 0) /* GPIO is not available */
 		return -ENODEV;
 
 	if (!request_region(block->runtime_reg + block->config_regs[offset],
 			    1, DRV_NAME)) {
-		dev_err(chip->dev, "Failed to request region 0x%04x.\n",
+		dev_err(chip->parent, "Failed to request region 0x%04x.\n",
 			block->runtime_reg + block->config_regs[offset]);
 		return -EBUSY;
 	}
@@ -158,7 +151,7 @@
 
 static void sch311x_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
-	struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+	struct sch311x_gpio_block *block = gpiochip_get_data(chip);
 
 	if (block->config_regs[offset] == 0) /* GPIO is not available */
 		return;
@@ -168,7 +161,7 @@
 
 static int sch311x_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+	struct sch311x_gpio_block *block = gpiochip_get_data(chip);
 	unsigned char data;
 
 	spin_lock(&block->lock);
@@ -192,7 +185,7 @@
 static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset,
 			     int value)
 {
-	struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+	struct sch311x_gpio_block *block = gpiochip_get_data(chip);
 
 	spin_lock(&block->lock);
 	 __sch311x_gpio_set(block, offset, value);
@@ -201,7 +194,7 @@
 
 static int sch311x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
-	struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+	struct sch311x_gpio_block *block = gpiochip_get_data(chip);
 
 	spin_lock(&block->lock);
 	outb(SCH311X_GPIO_CONF_IN, block->runtime_reg +
@@ -214,7 +207,7 @@
 static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
 				      int value)
 {
-	struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+	struct sch311x_gpio_block *block = gpiochip_get_data(chip);
 
 	spin_lock(&block->lock);
 
@@ -229,7 +222,7 @@
 
 static int sch311x_gpio_probe(struct platform_device *pdev)
 {
-	struct sch311x_pdev_data *pdata = pdev->dev.platform_data;
+	struct sch311x_pdev_data *pdata = dev_get_platdata(&pdev->dev);
 	struct sch311x_gpio_priv *priv;
 	struct sch311x_gpio_block *block;
 	int err, i;
@@ -261,13 +254,13 @@
 		block->chip.get = sch311x_gpio_get;
 		block->chip.set = sch311x_gpio_set;
 		block->chip.ngpio = 8;
-		block->chip.dev = &pdev->dev;
+		block->chip.parent = &pdev->dev;
 		block->chip.base = sch311x_gpio_blocks[i].base;
 		block->config_regs = sch311x_gpio_blocks[i].config_regs;
 		block->data_reg = sch311x_gpio_blocks[i].data_reg;
 		block->runtime_reg = pdata->runtime_reg;
 
-		err = gpiochip_add(&block->chip);
+		err = gpiochip_add_data(&block->chip, block);
 		if (err < 0) {
 			dev_err(&pdev->dev,
 				"Could not register gpiochip, %d\n", err);
@@ -289,7 +282,7 @@
 
 static int sch311x_gpio_remove(struct platform_device *pdev)
 {
-	struct sch311x_pdev_data *pdata = pdev->dev.platform_data;
+	struct sch311x_pdev_data *pdata = dev_get_platdata(&pdev->dev);
 	struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev);
 	int i;
 
diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c
index 34b02b4..e3cb677 100644
--- a/drivers/gpio/gpio-sodaville.c
+++ b/drivers/gpio/gpio-sodaville.c
@@ -10,7 +10,6 @@
  */
 
 #include <linux/errno.h>
-#include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/irq.h>
@@ -20,7 +19,7 @@
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/of_irq.h>
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
 
 #define DRV_NAME		"sdv_gpio"
 #define SDV_NUM_PUB_GPIOS	12
@@ -43,7 +42,7 @@
 	void __iomem *gpio_pub_base;
 	struct irq_domain *id;
 	struct irq_chip_generic *gc;
-	struct bgpio_chip bgpio;
+	struct gpio_chip chip;
 };
 
 static int sdv_gpio_pub_set_type(struct irq_data *d, unsigned int type)
@@ -226,14 +225,14 @@
 		writel(mux_val, sd->gpio_pub_base + GPMUXCTL);
 	}
 
-	ret = bgpio_init(&sd->bgpio, &pdev->dev, 4,
+	ret = bgpio_init(&sd->chip, &pdev->dev, 4,
 			sd->gpio_pub_base + GPINR, sd->gpio_pub_base + GPOUTR,
 			NULL, sd->gpio_pub_base + GPOER, NULL, 0);
 	if (ret)
 		goto unmap;
-	sd->bgpio.gc.ngpio = SDV_NUM_PUB_GPIOS;
+	sd->chip.ngpio = SDV_NUM_PUB_GPIOS;
 
-	ret = gpiochip_add(&sd->bgpio.gc);
+	ret = gpiochip_add_data(&sd->chip, sd);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "gpiochip_add() failed.\n");
 		goto unmap;
@@ -265,7 +264,7 @@
 	free_irq(pdev->irq, sd);
 	irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS);
 
-	gpiochip_remove(&sd->bgpio.gc);
+	gpiochip_remove(&sd->chip);
 	pci_release_region(pdev, GPIO_BAR);
 	iounmap(sd->gpio_pub_base);
 	pci_disable_device(pdev);
diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c
index 69ffca5..50fb090 100644
--- a/drivers/gpio/gpio-spear-spics.c
+++ b/drivers/gpio/gpio-spear-spics.c
@@ -62,8 +62,7 @@
 
 static void spics_set_value(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct spear_spics *spics = container_of(chip, struct spear_spics,
-			chip);
+	struct spear_spics *spics = gpiochip_get_data(chip);
 	u32 tmp;
 
 	/* select chip select from register */
@@ -94,8 +93,7 @@
 
 static int spics_request(struct gpio_chip *chip, unsigned offset)
 {
-	struct spear_spics *spics = container_of(chip, struct spear_spics,
-			chip);
+	struct spear_spics *spics = gpiochip_get_data(chip);
 	u32 tmp;
 
 	if (!spics->use_count++) {
@@ -110,8 +108,7 @@
 
 static void spics_free(struct gpio_chip *chip, unsigned offset)
 {
-	struct spear_spics *spics = container_of(chip, struct spear_spics,
-			chip);
+	struct spear_spics *spics = gpiochip_get_data(chip);
 	u32 tmp;
 
 	if (!--spics->use_count) {
@@ -164,11 +161,11 @@
 	spics->chip.get = spics_get_value;
 	spics->chip.set = spics_set_value;
 	spics->chip.label = dev_name(&pdev->dev);
-	spics->chip.dev = &pdev->dev;
+	spics->chip.parent = &pdev->dev;
 	spics->chip.owner = THIS_MODULE;
 	spics->last_off = -1;
 
-	ret = gpiochip_add(&spics->chip);
+	ret = gpiochip_add_data(&spics->chip, spics);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to add gpio chip\n");
 		return ret;
diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c
index 55e47828..83af1cb 100644
--- a/drivers/gpio/gpio-sta2x11.c
+++ b/drivers/gpio/gpio-sta2x11.c
@@ -74,7 +74,7 @@
 
 static void gsta_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
 {
-	struct gsta_gpio *chip = container_of(gpio, struct gsta_gpio, gpio);
+	struct gsta_gpio *chip = gpiochip_get_data(gpio);
 	struct gsta_regs __iomem *regs = __regs(chip, nr);
 	u32 bit = __bit(nr);
 
@@ -86,17 +86,17 @@
 
 static int gsta_gpio_get(struct gpio_chip *gpio, unsigned nr)
 {
-	struct gsta_gpio *chip = container_of(gpio, struct gsta_gpio, gpio);
+	struct gsta_gpio *chip = gpiochip_get_data(gpio);
 	struct gsta_regs __iomem *regs = __regs(chip, nr);
 	u32 bit = __bit(nr);
 
-	return readl(&regs->dat) & bit;
+	return !!(readl(&regs->dat) & bit);
 }
 
 static int gsta_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
 				      int val)
 {
-	struct gsta_gpio *chip = container_of(gpio, struct gsta_gpio, gpio);
+	struct gsta_gpio *chip = gpiochip_get_data(gpio);
 	struct gsta_regs __iomem *regs = __regs(chip, nr);
 	u32 bit = __bit(nr);
 
@@ -111,7 +111,7 @@
 
 static int gsta_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
 {
-	struct gsta_gpio *chip = container_of(gpio, struct gsta_gpio, gpio);
+	struct gsta_gpio *chip = gpiochip_get_data(gpio);
 	struct gsta_regs __iomem *regs = __regs(chip, nr);
 	u32 bit = __bit(nr);
 
@@ -121,7 +121,7 @@
 
 static int gsta_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
 {
-	struct gsta_gpio *chip = container_of(gpio, struct gsta_gpio, gpio);
+	struct gsta_gpio *chip = gpiochip_get_data(gpio);
 	return chip->irq_base + offset;
 }
 
@@ -409,7 +409,7 @@
 		goto err_free_descs;
 	}
 
-	err = gpiochip_add(&chip->gpio);
+	err = gpiochip_add_data(&chip->gpio, chip);
 	if (err < 0) {
 		dev_err(&dev->dev, "sta2x11 gpio: Can't register (%i)\n",
 			-err);
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index dabfb99..5197edf 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -36,14 +36,9 @@
 	u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
 };
 
-static inline struct stmpe_gpio *to_stmpe_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct stmpe_gpio, chip);
-}
-
 static int stmpe_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+	struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
 	struct stmpe *stmpe = stmpe_gpio->stmpe;
 	u8 reg = stmpe->regs[STMPE_IDX_GPMR_LSB] - (offset / 8);
 	u8 mask = 1 << (offset % 8);
@@ -58,7 +53,7 @@
 
 static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
 {
-	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+	struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
 	struct stmpe *stmpe = stmpe_gpio->stmpe;
 	int which = val ? STMPE_IDX_GPSR_LSB : STMPE_IDX_GPCR_LSB;
 	u8 reg = stmpe->regs[which] - (offset / 8);
@@ -77,7 +72,7 @@
 static int stmpe_gpio_direction_output(struct gpio_chip *chip,
 					 unsigned offset, int val)
 {
-	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+	struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
 	struct stmpe *stmpe = stmpe_gpio->stmpe;
 	u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
 	u8 mask = 1 << (offset % 8);
@@ -90,7 +85,7 @@
 static int stmpe_gpio_direction_input(struct gpio_chip *chip,
 					unsigned offset)
 {
-	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+	struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
 	struct stmpe *stmpe = stmpe_gpio->stmpe;
 	u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
 	u8 mask = 1 << (offset % 8);
@@ -100,7 +95,7 @@
 
 static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
-	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+	struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
 	struct stmpe *stmpe = stmpe_gpio->stmpe;
 
 	if (stmpe_gpio->norequest_mask & (1 << offset))
@@ -123,7 +118,7 @@
 static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
+	struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
 	int offset = d->hwirq;
 	int regoffset = offset / 8;
 	int mask = 1 << (offset % 8);
@@ -151,7 +146,7 @@
 static void stmpe_gpio_irq_lock(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
+	struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
 
 	mutex_lock(&stmpe_gpio->irq_lock);
 }
@@ -159,7 +154,7 @@
 static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
+	struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
 	struct stmpe *stmpe = stmpe_gpio->stmpe;
 	int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
 	static const u8 regmap[] = {
@@ -193,7 +188,7 @@
 static void stmpe_gpio_irq_mask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
+	struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
 	int offset = d->hwirq;
 	int regoffset = offset / 8;
 	int mask = 1 << (offset % 8);
@@ -204,7 +199,7 @@
 static void stmpe_gpio_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
+	struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
 	int offset = d->hwirq;
 	int regoffset = offset / 8;
 	int mask = 1 << (offset % 8);
@@ -216,7 +211,7 @@
 			       struct gpio_chip *gc,
 			       unsigned offset, unsigned gpio)
 {
-	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
+	struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
 	struct stmpe *stmpe = stmpe_gpio->stmpe;
 	const char *label = gpiochip_is_requested(gc, offset);
 	int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
@@ -356,7 +351,7 @@
 	stmpe_gpio->stmpe = stmpe;
 	stmpe_gpio->chip = template_chip;
 	stmpe_gpio->chip.ngpio = stmpe->num_gpios;
-	stmpe_gpio->chip.dev = &pdev->dev;
+	stmpe_gpio->chip.parent = &pdev->dev;
 	stmpe_gpio->chip.of_node = np;
 	stmpe_gpio->chip.base = -1;
 
@@ -375,7 +370,7 @@
 	if (ret)
 		goto out_free;
 
-	ret = gpiochip_add(&stmpe_gpio->chip);
+	ret = gpiochip_add_data(&stmpe_gpio->chip, stmpe_gpio);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
 		goto out_disable;
diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c
index 81bdbe7..d11dd48 100644
--- a/drivers/gpio/gpio-stp-xway.c
+++ b/drivers/gpio/gpio-stp-xway.c
@@ -100,8 +100,7 @@
  */
 static void xway_stp_set(struct gpio_chip *gc, unsigned gpio, int val)
 {
-	struct xway_stp *chip =
-		container_of(gc, struct xway_stp, gc);
+	struct xway_stp *chip = gpiochip_get_data(gc);
 
 	if (val)
 		chip->shadow |= BIT(gpio);
@@ -135,11 +134,10 @@
  */
 static int xway_stp_request(struct gpio_chip *gc, unsigned gpio)
 {
-	struct xway_stp *chip =
-		container_of(gc, struct xway_stp, gc);
+	struct xway_stp *chip = gpiochip_get_data(gc);
 
 	if ((gpio < 8) && (chip->reserved & BIT(gpio))) {
-		dev_err(gc->dev, "GPIO %d is driven by hardware\n", gpio);
+		dev_err(gc->parent, "GPIO %d is driven by hardware\n", gpio);
 		return -ENODEV;
 	}
 
@@ -214,7 +212,7 @@
 	if (IS_ERR(chip->virt))
 		return PTR_ERR(chip->virt);
 
-	chip->gc.dev = &pdev->dev;
+	chip->gc.parent = &pdev->dev;
 	chip->gc.label = "stp-xway";
 	chip->gc.direction_output = xway_stp_dir_out;
 	chip->gc.set = xway_stp_set;
@@ -260,7 +258,7 @@
 
 	ret = xway_stp_hw_init(chip);
 	if (!ret)
-		ret = gpiochip_add(&chip->gc);
+		ret = gpiochip_add_data(&chip->gc, chip);
 
 	if (!ret)
 		dev_info(&pdev->dev, "Init done\n");
diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c
index 76f9201..e6cff1c 100644
--- a/drivers/gpio/gpio-sx150x.c
+++ b/drivers/gpio/gpio-sx150x.c
@@ -32,8 +32,19 @@
 #define NO_UPDATE_PENDING	-1
 
 /* The chip models of sx150x */
-#define SX150X_456 0
-#define SX150X_789 1
+#define SX150X_123 0
+#define SX150X_456 1
+#define SX150X_789 2
+
+struct sx150x_123_pri {
+	u8 reg_pld_mode;
+	u8 reg_pld_table0;
+	u8 reg_pld_table1;
+	u8 reg_pld_table2;
+	u8 reg_pld_table3;
+	u8 reg_pld_table4;
+	u8 reg_advance;
+};
 
 struct sx150x_456_pri {
 	u8 reg_pld_mode;
@@ -65,6 +76,7 @@
 	u8 reg_sense;
 	u8 ngpios;
 	union {
+		struct sx150x_123_pri x123;
 		struct sx150x_456_pri x456;
 		struct sx150x_789_pri x789;
 	} pri;
@@ -142,12 +154,33 @@
 		},
 		.ngpios	= 16
 	},
+	[3] = { /* sx1502q */
+		.model = SX150X_123,
+		.reg_pullup	= 0x02,
+		.reg_pulldn	= 0x03,
+		.reg_dir	= 0x01,
+		.reg_data	= 0x00,
+		.reg_irq_mask	= 0x05,
+		.reg_irq_src	= 0x08,
+		.reg_sense	= 0x07,
+		.pri.x123 = {
+			.reg_pld_mode	= 0x10,
+			.reg_pld_table0	= 0x11,
+			.reg_pld_table1	= 0x12,
+			.reg_pld_table2	= 0x13,
+			.reg_pld_table3	= 0x14,
+			.reg_pld_table4	= 0x15,
+			.reg_advance	= 0xad,
+		},
+		.ngpios	= 8,
+	},
 };
 
 static const struct i2c_device_id sx150x_id[] = {
 	{"sx1508q", 0},
 	{"sx1509q", 1},
 	{"sx1506q", 2},
+	{"sx1502q", 3},
 	{}
 };
 MODULE_DEVICE_TABLE(i2c, sx150x_id);
@@ -156,15 +189,11 @@
 	{ .compatible = "semtech,sx1508q" },
 	{ .compatible = "semtech,sx1509q" },
 	{ .compatible = "semtech,sx1506q" },
+	{ .compatible = "semtech,sx1502q" },
 	{},
 };
 MODULE_DEVICE_TABLE(of, sx150x_of_match);
 
-struct sx150x_chip *to_sx150x(struct gpio_chip *gc)
-{
-	return container_of(gc, struct sx150x_chip, gpio_chip);
-}
-
 static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val)
 {
 	s32 err = i2c_smbus_write_byte_data(client, reg, val);
@@ -301,7 +330,7 @@
 
 static int sx150x_gpio_get(struct gpio_chip *gc, unsigned offset)
 {
-	struct sx150x_chip *chip = to_sx150x(gc);
+	struct sx150x_chip *chip = gpiochip_get_data(gc);
 	int status = -EINVAL;
 
 	if (!offset_is_oscio(chip, offset)) {
@@ -310,12 +339,12 @@
 		mutex_unlock(&chip->lock);
 	}
 
-	return status;
+	return (status < 0) ? status : !!status;
 }
 
 static void sx150x_gpio_set(struct gpio_chip *gc, unsigned offset, int val)
 {
-	struct sx150x_chip *chip = to_sx150x(gc);
+	struct sx150x_chip *chip = gpiochip_get_data(gc);
 
 	mutex_lock(&chip->lock);
 	if (offset_is_oscio(chip, offset))
@@ -327,7 +356,7 @@
 
 static int sx150x_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
 {
-	struct sx150x_chip *chip = to_sx150x(gc);
+	struct sx150x_chip *chip = gpiochip_get_data(gc);
 	int status = -EINVAL;
 
 	if (!offset_is_oscio(chip, offset)) {
@@ -342,7 +371,7 @@
 					unsigned offset,
 					int val)
 {
-	struct sx150x_chip *chip = to_sx150x(gc);
+	struct sx150x_chip *chip = gpiochip_get_data(gc);
 	int status = 0;
 
 	if (!offset_is_oscio(chip, offset)) {
@@ -355,7 +384,7 @@
 
 static void sx150x_irq_mask(struct irq_data *d)
 {
-	struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d));
+	struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	unsigned n = d->hwirq;
 
 	chip->irq_masked |= (1 << n);
@@ -364,7 +393,7 @@
 
 static void sx150x_irq_unmask(struct irq_data *d)
 {
-	struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d));
+	struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	unsigned n = d->hwirq;
 
 	chip->irq_masked &= ~(1 << n);
@@ -373,7 +402,7 @@
 
 static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type)
 {
-	struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d));
+	struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	unsigned n, val = 0;
 
 	if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
@@ -428,14 +457,14 @@
 
 static void sx150x_irq_bus_lock(struct irq_data *d)
 {
-	struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d));
+	struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d));
 
 	mutex_lock(&chip->lock);
 }
 
 static void sx150x_irq_bus_sync_unlock(struct irq_data *d)
 {
-	struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d));
+	struct sx150x_chip *chip = gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	unsigned n;
 
 	if (chip->irq_update == NO_UPDATE_PENDING)
@@ -473,7 +502,7 @@
 
 	chip->client                     = client;
 	chip->dev_cfg                    = &sx150x_devices[driver_data];
-	chip->gpio_chip.dev              = &client->dev;
+	chip->gpio_chip.parent              = &client->dev;
 	chip->gpio_chip.label            = client->name;
 	chip->gpio_chip.direction_input  = sx150x_gpio_direction_input;
 	chip->gpio_chip.direction_output = sx150x_gpio_direction_output;
@@ -545,10 +574,14 @@
 		err = sx150x_i2c_write(chip->client,
 				chip->dev_cfg->pri.x789.reg_misc,
 				0x01);
-	else
+	else if (chip->dev_cfg->model == SX150X_456)
 		err = sx150x_i2c_write(chip->client,
 				chip->dev_cfg->pri.x456.reg_advance,
 				0x04);
+	else
+		err = sx150x_i2c_write(chip->client,
+				chip->dev_cfg->pri.x123.reg_advance,
+				0x00);
 	if (err < 0)
 		return err;
 
@@ -574,13 +607,20 @@
 				pdata->io_polarity);
 		if (err < 0)
 			return err;
-	} else {
+	} else if (chip->dev_cfg->model == SX150X_456) {
 		/* Set all pins to work in normal mode */
 		err = sx150x_init_io(chip,
 				chip->dev_cfg->pri.x456.reg_pld_mode,
 				0);
 		if (err < 0)
 			return err;
+	} else {
+		/* Set all pins to work in normal mode */
+		err = sx150x_init_io(chip,
+				chip->dev_cfg->pri.x123.reg_pld_mode,
+				0);
+		if (err < 0)
+			return err;
 	}
 
 
@@ -647,7 +687,7 @@
 	if (rc < 0)
 		return rc;
 
-	rc = gpiochip_add(&chip->gpio_chip);
+	rc = gpiochip_add_data(&chip->gpio_chip, chip);
 	if (rc)
 		return rc;
 
@@ -680,7 +720,6 @@
 static struct i2c_driver sx150x_driver = {
 	.driver = {
 		.name = "sx150x",
-		.owner = THIS_MODULE,
 		.of_match_table = of_match_ptr(sx150x_of_match),
 	},
 	.probe    = sx150x_probe,
diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c
index 7b25fdf..e5c5b62 100644
--- a/drivers/gpio/gpio-syscon.c
+++ b/drivers/gpio/gpio-syscon.c
@@ -59,14 +59,9 @@
 	u32				dir_reg_offset;
 };
 
-static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct syscon_gpio_priv, chip);
-}
-
 static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+	struct syscon_gpio_priv *priv = gpiochip_get_data(chip);
 	unsigned int val, offs;
 	int ret;
 
@@ -82,7 +77,7 @@
 
 static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
 {
-	struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+	struct syscon_gpio_priv *priv = gpiochip_get_data(chip);
 	unsigned int offs;
 
 	offs = priv->dreg_offset + priv->data->dat_bit_offset + offset;
@@ -95,7 +90,7 @@
 
 static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
 {
-	struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+	struct syscon_gpio_priv *priv = gpiochip_get_data(chip);
 
 	if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
 		unsigned int offs;
@@ -113,7 +108,7 @@
 
 static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
 {
-	struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+	struct syscon_gpio_priv *priv = gpiochip_get_data(chip);
 
 	if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
 		unsigned int offs;
@@ -144,7 +139,7 @@
 
 static void keystone_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
 {
-	struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+	struct syscon_gpio_priv *priv = gpiochip_get_data(chip);
 	unsigned int offs;
 	int ret;
 
@@ -159,7 +154,7 @@
 			BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT,
 			BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT);
 	if (ret < 0)
-		dev_err(chip->dev, "gpio write failed ret(%d)\n", ret);
+		dev_err(chip->parent, "gpio write failed ret(%d)\n", ret);
 }
 
 static const struct syscon_gpio_data keystone_dsp_gpio = {
@@ -228,7 +223,7 @@
 		priv->dir_reg_offset <<= 3;
 	}
 
-	priv->chip.dev = dev;
+	priv->chip.parent = dev;
 	priv->chip.owner = THIS_MODULE;
 	priv->chip.label = dev_name(dev);
 	priv->chip.base = -1;
@@ -243,7 +238,7 @@
 
 	platform_set_drvdata(pdev, priv);
 
-	return gpiochip_add(&priv->chip);
+	return gpiochip_add_data(&priv->chip, priv);
 }
 
 static int syscon_gpio_remove(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c
index 4356e6c..5eaec20 100644
--- a/drivers/gpio/gpio-tb10x.c
+++ b/drivers/gpio/gpio-tb10x.c
@@ -87,14 +87,9 @@
 	spin_unlock_irqrestore(&gpio->spinlock, flags);
 }
 
-static inline struct tb10x_gpio *to_tb10x_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct tb10x_gpio, gc);
-}
-
 static int tb10x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
-	struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip);
+	struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
 	int mask = BIT(offset);
 	int val = TB10X_GPIO_DIR_IN << offset;
 
@@ -105,7 +100,7 @@
 
 static int tb10x_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip);
+	struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
 	int val;
 
 	val = tb10x_reg_read(tb10x_gpio, OFFSET_TO_REG_DATA);
@@ -118,7 +113,7 @@
 
 static void tb10x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip);
+	struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
 	int mask = BIT(offset);
 	int val = value << offset;
 
@@ -128,7 +123,7 @@
 static int tb10x_gpio_direction_out(struct gpio_chip *chip,
 					unsigned offset, int value)
 {
-	struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip);
+	struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
 	int mask = BIT(offset);
 	int val = TB10X_GPIO_DIR_OUT << offset;
 
@@ -140,7 +135,7 @@
 
 static int tb10x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip);
+	struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
 
 	return irq_create_mapping(tb10x_gpio->domain, offset);
 }
@@ -197,7 +192,7 @@
 		return PTR_ERR(tb10x_gpio->base);
 
 	tb10x_gpio->gc.label		= of_node_full_name(dn);
-	tb10x_gpio->gc.dev		= &pdev->dev;
+	tb10x_gpio->gc.parent		= &pdev->dev;
 	tb10x_gpio->gc.owner		= THIS_MODULE;
 	tb10x_gpio->gc.direction_input	= tb10x_gpio_direction_in;
 	tb10x_gpio->gc.get		= tb10x_gpio_get;
@@ -210,7 +205,7 @@
 	tb10x_gpio->gc.can_sleep	= false;
 
 
-	ret = gpiochip_add(&tb10x_gpio->gc);
+	ret = gpiochip_add_data(&tb10x_gpio->gc, tb10x_gpio);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Could not add gpiochip.\n");
 		goto fail_gpiochip_registration;
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index d1d585d..05a27ec 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -34,14 +34,9 @@
 	u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
 };
 
-static inline struct tc3589x_gpio *to_tc3589x_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct tc3589x_gpio, chip);
-}
-
 static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
+	struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
 	struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
 	u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2;
 	u8 mask = 1 << (offset % 8);
@@ -51,12 +46,12 @@
 	if (ret < 0)
 		return ret;
 
-	return ret & mask;
+	return !!(ret & mask);
 }
 
 static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
 {
-	struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
+	struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
 	struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
 	u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2;
 	unsigned pos = offset % 8;
@@ -68,7 +63,7 @@
 static int tc3589x_gpio_direction_output(struct gpio_chip *chip,
 					 unsigned offset, int val)
 {
-	struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
+	struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
 	struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
 	u8 reg = TC3589x_GPIODIR0 + offset / 8;
 	unsigned pos = offset % 8;
@@ -81,7 +76,7 @@
 static int tc3589x_gpio_direction_input(struct gpio_chip *chip,
 					unsigned offset)
 {
-	struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
+	struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
 	struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
 	u8 reg = TC3589x_GPIODIR0 + offset / 8;
 	unsigned pos = offset % 8;
@@ -102,7 +97,7 @@
 static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc);
+	struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
 	int offset = d->hwirq;
 	int regoffset = offset / 8;
 	int mask = 1 << (offset % 8);
@@ -130,7 +125,7 @@
 static void tc3589x_gpio_irq_lock(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc);
+	struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
 
 	mutex_lock(&tc3589x_gpio->irq_lock);
 }
@@ -138,7 +133,7 @@
 static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc);
+	struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
 	struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
 	static const u8 regmap[] = {
 		[REG_IBE]	= TC3589x_GPIOIBE0,
@@ -167,7 +162,7 @@
 static void tc3589x_gpio_irq_mask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc);
+	struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
 	int offset = d->hwirq;
 	int regoffset = offset / 8;
 	int mask = 1 << (offset % 8);
@@ -178,7 +173,7 @@
 static void tc3589x_gpio_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc);
+	struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
 	int offset = d->hwirq;
 	int regoffset = offset / 8;
 	int mask = 1 << (offset % 8);
@@ -258,7 +253,7 @@
 
 	tc3589x_gpio->chip = template_chip;
 	tc3589x_gpio->chip.ngpio = tc3589x->num_gpio;
-	tc3589x_gpio->chip.dev = &pdev->dev;
+	tc3589x_gpio->chip.parent = &pdev->dev;
 	tc3589x_gpio->chip.base = -1;
 	tc3589x_gpio->chip.of_node = np;
 
@@ -277,7 +272,7 @@
 		return ret;
 	}
 
-	ret = gpiochip_add(&tc3589x_gpio->chip);
+	ret = gpiochip_add_data(&tc3589x_gpio->chip, tc3589x_gpio);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
 		return ret;
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 896bf29..9a1a7e2 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -545,7 +545,7 @@
 
 	tegra_gpio_chip.of_node = pdev->dev.of_node;
 
-	ret = gpiochip_add(&tegra_gpio_chip);
+	ret = gpiochip_add_data(&tegra_gpio_chip, NULL);
 	if (ret < 0) {
 		irq_domain_remove(irq_domain);
 		return ret;
diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c
index 30653e6..a6de10c 100644
--- a/drivers/gpio/gpio-timberdale.c
+++ b/drivers/gpio/gpio-timberdale.c
@@ -53,7 +53,7 @@
 static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index,
 	unsigned offset, bool enabled)
 {
-	struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio);
+	struct timbgpio *tgpio = gpiochip_get_data(gpio);
 	u32 reg;
 
 	spin_lock(&tgpio->lock);
@@ -77,7 +77,7 @@
 
 static int timbgpio_gpio_get(struct gpio_chip *gpio, unsigned nr)
 {
-	struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio);
+	struct timbgpio *tgpio = gpiochip_get_data(gpio);
 	u32 value;
 
 	value = ioread32(tgpio->membase + TGPIOVAL);
@@ -98,7 +98,7 @@
 
 static int timbgpio_to_irq(struct gpio_chip *gpio, unsigned offset)
 {
-	struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio);
+	struct timbgpio *tgpio = gpiochip_get_data(gpio);
 
 	if (tgpio->irq_base <= 0)
 		return -EINVAL;
@@ -268,7 +268,7 @@
 
 	gc->label = dev_name(&pdev->dev);
 	gc->owner = THIS_MODULE;
-	gc->dev = &pdev->dev;
+	gc->parent = &pdev->dev;
 	gc->direction_input = timbgpio_gpio_direction_input;
 	gc->get = timbgpio_gpio_get;
 	gc->direction_output = timbgpio_gpio_direction_output;
@@ -279,7 +279,7 @@
 	gc->ngpio = pdata->nr_pins;
 	gc->can_sleep = false;
 
-	err = gpiochip_add(gc);
+	err = gpiochip_add_data(gc, tgpio);
 	if (err)
 		return err;
 
diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c
index 9c9238e..87de548 100644
--- a/drivers/gpio/gpio-tps6586x.c
+++ b/drivers/gpio/gpio-tps6586x.c
@@ -38,14 +38,9 @@
 	struct device *parent;
 };
 
-static inline struct tps6586x_gpio *to_tps6586x_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct tps6586x_gpio, gpio_chip);
-}
-
 static int tps6586x_gpio_get(struct gpio_chip *gc, unsigned offset)
 {
-	struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc);
+	struct tps6586x_gpio *tps6586x_gpio = gpiochip_get_data(gc);
 	uint8_t val;
 	int ret;
 
@@ -59,7 +54,7 @@
 static void tps6586x_gpio_set(struct gpio_chip *gc, unsigned offset,
 			      int value)
 {
-	struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc);
+	struct tps6586x_gpio *tps6586x_gpio = gpiochip_get_data(gc);
 
 	tps6586x_update(tps6586x_gpio->parent, TPS6586X_GPIOSET2,
 			value << offset, 1 << offset);
@@ -68,7 +63,7 @@
 static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
 				int value)
 {
-	struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc);
+	struct tps6586x_gpio *tps6586x_gpio = gpiochip_get_data(gc);
 	uint8_t val, mask;
 
 	tps6586x_gpio_set(gc, offset, value);
@@ -82,7 +77,7 @@
 
 static int tps6586x_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 {
-	struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc);
+	struct tps6586x_gpio *tps6586x_gpio = gpiochip_get_data(gc);
 
 	return tps6586x_irq_get_virq(tps6586x_gpio->parent,
 				TPS6586X_INT_PLDO_0 + offset);
@@ -104,7 +99,7 @@
 
 	tps6586x_gpio->gpio_chip.owner = THIS_MODULE;
 	tps6586x_gpio->gpio_chip.label = pdev->name;
-	tps6586x_gpio->gpio_chip.dev = &pdev->dev;
+	tps6586x_gpio->gpio_chip.parent = &pdev->dev;
 	tps6586x_gpio->gpio_chip.ngpio = 4;
 	tps6586x_gpio->gpio_chip.can_sleep = true;
 
@@ -122,7 +117,7 @@
 	else
 		tps6586x_gpio->gpio_chip.base = -1;
 
-	ret = gpiochip_add(&tps6586x_gpio->gpio_chip);
+	ret = gpiochip_add_data(&tps6586x_gpio->gpio_chip, tps6586x_gpio);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
 		return ret;
diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c
index 88f1f5f..e81eee7 100644
--- a/drivers/gpio/gpio-tps65910.c
+++ b/drivers/gpio/gpio-tps65910.c
@@ -27,14 +27,9 @@
 	struct tps65910 *tps65910;
 };
 
-static inline struct tps65910_gpio *to_tps65910_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct tps65910_gpio, gpio_chip);
-}
-
 static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset)
 {
-	struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
+	struct tps65910_gpio *tps65910_gpio = gpiochip_get_data(gc);
 	struct tps65910 *tps65910 = tps65910_gpio->tps65910;
 	unsigned int val;
 
@@ -49,7 +44,7 @@
 static void tps65910_gpio_set(struct gpio_chip *gc, unsigned offset,
 			      int value)
 {
-	struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
+	struct tps65910_gpio *tps65910_gpio = gpiochip_get_data(gc);
 	struct tps65910 *tps65910 = tps65910_gpio->tps65910;
 
 	if (value)
@@ -63,7 +58,7 @@
 static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset,
 				int value)
 {
-	struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
+	struct tps65910_gpio *tps65910_gpio = gpiochip_get_data(gc);
 	struct tps65910 *tps65910 = tps65910_gpio->tps65910;
 
 	/* Set the initial value */
@@ -75,7 +70,7 @@
 
 static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset)
 {
-	struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
+	struct tps65910_gpio *tps65910_gpio = gpiochip_get_data(gc);
 	struct tps65910 *tps65910 = tps65910_gpio->tps65910;
 
 	return tps65910_reg_clear_bits(tps65910, TPS65910_GPIO0 + offset,
@@ -146,7 +141,7 @@
 	tps65910_gpio->gpio_chip.direction_output = tps65910_gpio_output;
 	tps65910_gpio->gpio_chip.set	= tps65910_gpio_set;
 	tps65910_gpio->gpio_chip.get	= tps65910_gpio_get;
-	tps65910_gpio->gpio_chip.dev = &pdev->dev;
+	tps65910_gpio->gpio_chip.parent = &pdev->dev;
 #ifdef CONFIG_OF_GPIO
 	tps65910_gpio->gpio_chip.of_node = tps65910->dev->of_node;
 #endif
@@ -175,7 +170,7 @@
 	}
 
 skip_init:
-	ret = gpiochip_add(&tps65910_gpio->gpio_chip);
+	ret = gpiochip_add_data(&tps65910_gpio->gpio_chip, tps65910_gpio);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
 		return ret;
diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c
index 9cdbc0c..4f2029c 100644
--- a/drivers/gpio/gpio-tps65912.c
+++ b/drivers/gpio/gpio-tps65912.c
@@ -26,11 +26,9 @@
 	struct gpio_chip gpio_chip;
 };
 
-#define to_tgd(gc) container_of(gc, struct tps65912_gpio_data, gpio_chip)
-
 static int tps65912_gpio_get(struct gpio_chip *gc, unsigned offset)
 {
-	struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+	struct tps65912_gpio_data *tps65912_gpio = gpiochip_get_data(gc);
 	struct tps65912 *tps65912 = tps65912_gpio->tps65912;
 	int val;
 
@@ -45,7 +43,7 @@
 static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset,
 			      int value)
 {
-	struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+	struct tps65912_gpio_data *tps65912_gpio = gpiochip_get_data(gc);
 	struct tps65912 *tps65912 = tps65912_gpio->tps65912;
 
 	if (value)
@@ -59,7 +57,7 @@
 static int tps65912_gpio_output(struct gpio_chip *gc, unsigned offset,
 				int value)
 {
-	struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+	struct tps65912_gpio_data *tps65912_gpio = gpiochip_get_data(gc);
 	struct tps65912 *tps65912 = tps65912_gpio->tps65912;
 
 	/* Set the initial value */
@@ -71,7 +69,7 @@
 
 static int tps65912_gpio_input(struct gpio_chip *gc, unsigned offset)
 {
-	struct tps65912_gpio_data *tps65912_gpio = to_tgd(gc);
+	struct tps65912_gpio_data *tps65912_gpio = gpiochip_get_data(gc);
 	struct tps65912 *tps65912 = tps65912_gpio->tps65912;
 
 	return tps65912_clear_bits(tps65912, TPS65912_GPIO1 + offset,
@@ -104,11 +102,11 @@
 
 	tps65912_gpio->tps65912 = tps65912;
 	tps65912_gpio->gpio_chip = template_chip;
-	tps65912_gpio->gpio_chip.dev = &pdev->dev;
+	tps65912_gpio->gpio_chip.parent = &pdev->dev;
 	if (pdata && pdata->gpio_base)
 		tps65912_gpio->gpio_chip.base = pdata->gpio_base;
 
-	ret = gpiochip_add(&tps65912_gpio->gpio_chip);
+	ret = gpiochip_add_data(&tps65912_gpio->gpio_chip, tps65912_gpio);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Failed to register gpiochip, %d\n", ret);
 		return ret;
diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c
index b29a102..5f94508 100644
--- a/drivers/gpio/gpio-ts5500.c
+++ b/drivers/gpio/gpio-ts5500.c
@@ -185,11 +185,6 @@
 	TS5500_DIO_IN_IRQ(0x73, 7, 1),
 };
 
-static inline struct ts5500_priv *ts5500_gc_to_priv(struct gpio_chip *chip)
-{
-	return container_of(chip, struct ts5500_priv, gpio_chip);
-}
-
 static inline void ts5500_set_mask(u8 mask, u8 addr)
 {
 	u8 val = inb(addr);
@@ -206,7 +201,7 @@
 
 static int ts5500_gpio_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct ts5500_priv *priv = ts5500_gc_to_priv(chip);
+	struct ts5500_priv *priv = gpiochip_get_data(chip);
 	const struct ts5500_dio line = priv->pinout[offset];
 	unsigned long flags;
 
@@ -225,7 +220,7 @@
 
 static int ts5500_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct ts5500_priv *priv = ts5500_gc_to_priv(chip);
+	struct ts5500_priv *priv = gpiochip_get_data(chip);
 	const struct ts5500_dio line = priv->pinout[offset];
 
 	return !!(inb(line.value_addr) & line.value_mask);
@@ -233,7 +228,7 @@
 
 static int ts5500_gpio_output(struct gpio_chip *chip, unsigned offset, int val)
 {
-	struct ts5500_priv *priv = ts5500_gc_to_priv(chip);
+	struct ts5500_priv *priv = gpiochip_get_data(chip);
 	const struct ts5500_dio line = priv->pinout[offset];
 	unsigned long flags;
 
@@ -255,7 +250,7 @@
 
 static void ts5500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
 {
-	struct ts5500_priv *priv = ts5500_gc_to_priv(chip);
+	struct ts5500_priv *priv = gpiochip_get_data(chip);
 	const struct ts5500_dio line = priv->pinout[offset];
 	unsigned long flags;
 
@@ -269,7 +264,7 @@
 
 static int ts5500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct ts5500_priv *priv = ts5500_gc_to_priv(chip);
+	struct ts5500_priv *priv = gpiochip_get_data(chip);
 	const struct ts5500_dio *block = priv->pinout;
 	const struct ts5500_dio line = block[offset];
 
@@ -315,7 +310,8 @@
 	else if (priv->hwirq == 1)
 		ts5500_clear_mask(BIT(6), 0x7d); /* LCD_RS on IRQ1 */
 	else
-		dev_err(priv->gpio_chip.dev, "invalid hwirq %d\n", priv->hwirq);
+		dev_err(priv->gpio_chip.parent, "invalid hwirq %d\n",
+			priv->hwirq);
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
@@ -346,7 +342,7 @@
 
 	priv->gpio_chip.owner = THIS_MODULE;
 	priv->gpio_chip.label = name;
-	priv->gpio_chip.dev = dev;
+	priv->gpio_chip.parent = dev;
 	priv->gpio_chip.direction_input = ts5500_gpio_input;
 	priv->gpio_chip.direction_output = ts5500_gpio_output;
 	priv->gpio_chip.get = ts5500_gpio_get;
@@ -413,7 +409,7 @@
 		break;
 	}
 
-	ret = gpiochip_add(&priv->gpio_chip);
+	ret = gpiochip_add_data(&priv->gpio_chip, priv);
 	if (ret) {
 		dev_err(dev, "failed to register the gpio chip\n");
 		return ret;
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c
index 9e1dbb9..4b807b0 100644
--- a/drivers/gpio/gpio-twl4030.c
+++ b/drivers/gpio/gpio-twl4030.c
@@ -76,11 +76,6 @@
 
 /*----------------------------------------------------------------------*/
 
-static inline struct gpio_twl4030_priv *to_gpio_twl4030(struct gpio_chip *chip)
-{
-	return container_of(chip, struct gpio_twl4030_priv, gpio_chip);
-}
-
 /*
  * To configure TWL4030 GPIO module registers
  */
@@ -205,7 +200,7 @@
 
 static int twl_request(struct gpio_chip *chip, unsigned offset)
 {
-	struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+	struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
 	int status = 0;
 
 	mutex_lock(&priv->mutex);
@@ -256,7 +251,7 @@
 		/* optionally have the first two GPIOs switch vMMC1
 		 * and vMMC2 power supplies based on card presence.
 		 */
-		pdata = dev_get_platdata(chip->dev);
+		pdata = dev_get_platdata(chip->parent);
 		if (pdata)
 			value |= pdata->mmc_cd & 0x03;
 
@@ -273,7 +268,7 @@
 
 static void twl_free(struct gpio_chip *chip, unsigned offset)
 {
-	struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+	struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
 
 	mutex_lock(&priv->mutex);
 	if (offset >= TWL4030_GPIO_MAX) {
@@ -293,7 +288,7 @@
 
 static int twl_direction_in(struct gpio_chip *chip, unsigned offset)
 {
-	struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+	struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
 	int ret;
 
 	mutex_lock(&priv->mutex);
@@ -312,7 +307,7 @@
 
 static int twl_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+	struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
 	int ret;
 	int status = 0;
 
@@ -327,7 +322,7 @@
 	else
 		status = twl4030_get_gpio_datain(offset);
 
-	ret = (status <= 0) ? 0 : 1;
+	ret = (status < 0) ? status : !!status;
 out:
 	mutex_unlock(&priv->mutex);
 	return ret;
@@ -335,7 +330,7 @@
 
 static void twl_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+	struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
 
 	mutex_lock(&priv->mutex);
 	if (offset < TWL4030_GPIO_MAX)
@@ -353,7 +348,7 @@
 
 static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+	struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
 	int ret = 0;
 
 	mutex_lock(&priv->mutex);
@@ -379,7 +374,7 @@
 
 static int twl_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+	struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
 
 	return (priv->irq_base && (offset < TWL4030_GPIO_MAX))
 		? (priv->irq_base + offset)
@@ -509,7 +504,7 @@
 	priv->gpio_chip = template_chip;
 	priv->gpio_chip.base = -1;
 	priv->gpio_chip.ngpio = TWL4030_GPIO_MAX;
-	priv->gpio_chip.dev = &pdev->dev;
+	priv->gpio_chip.parent = &pdev->dev;
 
 	mutex_init(&priv->mutex);
 
@@ -544,7 +539,7 @@
 	if (pdata->use_leds)
 		priv->gpio_chip.ngpio += 2;
 
-	ret = gpiochip_add(&priv->gpio_chip);
+	ret = gpiochip_add_data(&priv->gpio_chip, priv);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
 		priv->gpio_chip.ngpio = 0;
diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c
index c946e7e..8e9e985 100644
--- a/drivers/gpio/gpio-twl6040.c
+++ b/drivers/gpio/gpio-twl6040.c
@@ -36,7 +36,7 @@
 
 static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct twl6040 *twl6040 = dev_get_drvdata(chip->dev->parent);
+	struct twl6040 *twl6040 = dev_get_drvdata(chip->parent->parent);
 	int ret = 0;
 
 	ret = twl6040_reg_read(twl6040, TWL6040_REG_GPOCTL);
@@ -55,7 +55,7 @@
 
 static void twl6040gpo_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct twl6040 *twl6040 = dev_get_drvdata(chip->dev->parent);
+	struct twl6040 *twl6040 = dev_get_drvdata(chip->parent->parent);
 	int ret;
 	u8 gpoctl;
 
@@ -95,12 +95,12 @@
 	else
 		twl6040gpo_chip.ngpio = 1; /* twl6041 have 1 GPO */
 
-	twl6040gpo_chip.dev = &pdev->dev;
+	twl6040gpo_chip.parent = &pdev->dev;
 #ifdef CONFIG_OF_GPIO
 	twl6040gpo_chip.of_node = twl6040_core_dev->of_node;
 #endif
 
-	ret = gpiochip_add(&twl6040gpo_chip);
+	ret = gpiochip_add_data(&twl6040gpo_chip, NULL);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
 		twl6040gpo_chip.ngpio = 0;
diff --git a/drivers/gpio/gpio-tz1090-pdc.c b/drivers/gpio/gpio-tz1090-pdc.c
index 3623d00..5b77817 100644
--- a/drivers/gpio/gpio-tz1090-pdc.c
+++ b/drivers/gpio/gpio-tz1090-pdc.c
@@ -49,7 +49,6 @@
 	void __iomem *reg;
 	int irq[GPIO_PDC_NIRQ];
 };
-#define to_pdc(c)	container_of(c, struct tz1090_pdc_gpio, chip)
 
 /* Register accesses into the PDC MMIO area */
 
@@ -70,7 +69,7 @@
 static int tz1090_pdc_gpio_direction_input(struct gpio_chip *chip,
 					   unsigned int offset)
 {
-	struct tz1090_pdc_gpio *priv = to_pdc(chip);
+	struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
 	u32 value;
 	int lstat;
 
@@ -87,7 +86,7 @@
 					    unsigned int offset,
 					    int output_value)
 {
-	struct tz1090_pdc_gpio *priv = to_pdc(chip);
+	struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
 	u32 value;
 	int lstat;
 
@@ -112,14 +111,14 @@
 
 static int tz1090_pdc_gpio_get(struct gpio_chip *chip, unsigned int offset)
 {
-	struct tz1090_pdc_gpio *priv = to_pdc(chip);
-	return pdc_read(priv, REG_SOC_GPIO_STATUS) & BIT(offset);
+	struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
+	return !!(pdc_read(priv, REG_SOC_GPIO_STATUS) & BIT(offset));
 }
 
 static void tz1090_pdc_gpio_set(struct gpio_chip *chip, unsigned int offset,
 				int output_value)
 {
-	struct tz1090_pdc_gpio *priv = to_pdc(chip);
+	struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
 	u32 value;
 	int lstat;
 
@@ -139,7 +138,7 @@
 
 static int tz1090_pdc_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
 {
-	struct tz1090_pdc_gpio *priv = to_pdc(chip);
+	struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
 	unsigned int syswake = offset - GPIO_PDC_IRQ_FIRST;
 	int irq;
 
@@ -188,7 +187,7 @@
 
 	/* Set up GPIO chip */
 	priv->chip.label		= "tz1090-pdc-gpio";
-	priv->chip.dev			= &pdev->dev;
+	priv->chip.parent		= &pdev->dev;
 	priv->chip.direction_input	= tz1090_pdc_gpio_direction_input;
 	priv->chip.direction_output	= tz1090_pdc_gpio_direction_output;
 	priv->chip.get			= tz1090_pdc_gpio_get;
@@ -207,7 +206,7 @@
 		priv->irq[i] = irq_of_parse_and_map(np, i);
 
 	/* Add the GPIO bank */
-	gpiochip_add(&priv->chip);
+	gpiochip_add_data(&priv->chip, priv);
 
 	return 0;
 }
diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c
index 87bb1b1..ca958e0 100644
--- a/drivers/gpio/gpio-tz1090.c
+++ b/drivers/gpio/gpio-tz1090.c
@@ -62,7 +62,6 @@
 	int irq;
 	char label[16];
 };
-#define to_bank(c)	container_of(c, struct tz1090_gpio_bank, chip)
 
 /**
  * struct tz1090_gpio - Overall GPIO device private data
@@ -187,7 +186,7 @@
 static int tz1090_gpio_direction_input(struct gpio_chip *chip,
 				       unsigned int offset)
 {
-	struct tz1090_gpio_bank *bank = to_bank(chip);
+	struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
 	tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset);
 
 	return 0;
@@ -196,7 +195,7 @@
 static int tz1090_gpio_direction_output(struct gpio_chip *chip,
 					unsigned int offset, int output_value)
 {
-	struct tz1090_gpio_bank *bank = to_bank(chip);
+	struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
 	int lstat;
 
 	__global_lock2(lstat);
@@ -212,9 +211,9 @@
  */
 static int tz1090_gpio_get(struct gpio_chip *chip, unsigned int offset)
 {
-	struct tz1090_gpio_bank *bank = to_bank(chip);
+	struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
 
-	return tz1090_gpio_read_bit(bank, REG_GPIO_DIN, offset);
+	return !!tz1090_gpio_read_bit(bank, REG_GPIO_DIN, offset);
 }
 
 /*
@@ -223,14 +222,14 @@
 static void tz1090_gpio_set(struct gpio_chip *chip, unsigned int offset,
 			    int output_value)
 {
-	struct tz1090_gpio_bank *bank = to_bank(chip);
+	struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
 
 	tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value);
 }
 
 static int tz1090_gpio_request(struct gpio_chip *chip, unsigned int offset)
 {
-	struct tz1090_gpio_bank *bank = to_bank(chip);
+	struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
 	int ret;
 
 	ret = pinctrl_request_gpio(chip->base + offset);
@@ -245,7 +244,7 @@
 
 static void tz1090_gpio_free(struct gpio_chip *chip, unsigned int offset)
 {
-	struct tz1090_gpio_bank *bank = to_bank(chip);
+	struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
 
 	pinctrl_free_gpio(chip->base + offset);
 
@@ -254,7 +253,7 @@
 
 static int tz1090_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
 {
-	struct tz1090_gpio_bank *bank = to_bank(chip);
+	struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
 
 	if (!bank->domain)
 		return -EINVAL;
@@ -425,7 +424,7 @@
 	snprintf(bank->label, sizeof(bank->label), "tz1090-gpio-%u",
 		 info->index);
 	bank->chip.label		= bank->label;
-	bank->chip.dev			= dev;
+	bank->chip.parent		= dev;
 	bank->chip.direction_input	= tz1090_gpio_direction_input;
 	bank->chip.direction_output	= tz1090_gpio_direction_output;
 	bank->chip.get			= tz1090_gpio_get;
@@ -440,7 +439,7 @@
 	bank->chip.ngpio		= 30;
 
 	/* Add the GPIO bank */
-	gpiochip_add(&bank->chip);
+	gpiochip_add_data(&bank->chip, bank);
 
 	/* Get the GPIO bank IRQ if provided */
 	bank->irq = irq_of_parse_and_map(np, 0);
diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c
index d502825..2c5cd46 100644
--- a/drivers/gpio/gpio-ucb1400.c
+++ b/drivers/gpio/gpio-ucb1400.c
@@ -15,7 +15,7 @@
 static int ucb1400_gpio_dir_in(struct gpio_chip *gc, unsigned off)
 {
 	struct ucb1400_gpio *gpio;
-	gpio = container_of(gc, struct ucb1400_gpio, gc);
+	gpio = gpiochip_get_data(gc);
 	ucb1400_gpio_set_direction(gpio->ac97, off, 0);
 	return 0;
 }
@@ -23,7 +23,7 @@
 static int ucb1400_gpio_dir_out(struct gpio_chip *gc, unsigned off, int val)
 {
 	struct ucb1400_gpio *gpio;
-	gpio = container_of(gc, struct ucb1400_gpio, gc);
+	gpio = gpiochip_get_data(gc);
 	ucb1400_gpio_set_direction(gpio->ac97, off, 1);
 	ucb1400_gpio_set_value(gpio->ac97, off, val);
 	return 0;
@@ -32,14 +32,15 @@
 static int ucb1400_gpio_get(struct gpio_chip *gc, unsigned off)
 {
 	struct ucb1400_gpio *gpio;
-	gpio = container_of(gc, struct ucb1400_gpio, gc);
-	return ucb1400_gpio_get_value(gpio->ac97, off);
+
+	gpio = gpiochip_get_data(gc);
+	return !!ucb1400_gpio_get_value(gpio->ac97, off);
 }
 
 static void ucb1400_gpio_set(struct gpio_chip *gc, unsigned off, int val)
 {
 	struct ucb1400_gpio *gpio;
-	gpio = container_of(gc, struct ucb1400_gpio, gc);
+	gpio = gpiochip_get_data(gc);
 	ucb1400_gpio_set_value(gpio->ac97, off, val);
 }
 
@@ -66,7 +67,7 @@
 	ucb->gc.set = ucb1400_gpio_set;
 	ucb->gc.can_sleep = true;
 
-	err = gpiochip_add(&ucb->gc);
+	err = gpiochip_add_data(&ucb->gc, ucb);
 	if (err)
 		goto err;
 
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index 87b950c..6284bdb 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -62,11 +62,6 @@
 
 static struct irq_chip vf610_gpio_irq_chip;
 
-static struct vf610_gpio_port *to_vf610_gp(struct gpio_chip *gc)
-{
-	return container_of(gc, struct vf610_gpio_port, gc);
-}
-
 static const struct of_device_id vf610_gpio_dt_ids[] = {
 	{ .compatible = "fsl,vf610-gpio" },
 	{ /* sentinel */ }
@@ -84,14 +79,14 @@
 
 static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio)
 {
-	struct vf610_gpio_port *port = to_vf610_gp(gc);
+	struct vf610_gpio_port *port = gpiochip_get_data(gc);
 
 	return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR) & BIT(gpio));
 }
 
 static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
 {
-	struct vf610_gpio_port *port = to_vf610_gp(gc);
+	struct vf610_gpio_port *port = gpiochip_get_data(gc);
 	unsigned long mask = BIT(gpio);
 
 	if (val)
@@ -116,7 +111,7 @@
 static void vf610_gpio_irq_handler(struct irq_desc *desc)
 {
 	struct vf610_gpio_port *port =
-		to_vf610_gp(irq_desc_get_handler_data(desc));
+		gpiochip_get_data(irq_desc_get_handler_data(desc));
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	int pin;
 	unsigned long irq_isfr;
@@ -137,7 +132,7 @@
 static void vf610_gpio_irq_ack(struct irq_data *d)
 {
 	struct vf610_gpio_port *port =
-		to_vf610_gp(irq_data_get_irq_chip_data(d));
+		gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	int gpio = d->hwirq;
 
 	vf610_gpio_writel(BIT(gpio), port->base + PORT_ISFR);
@@ -146,7 +141,7 @@
 static int vf610_gpio_irq_set_type(struct irq_data *d, u32 type)
 {
 	struct vf610_gpio_port *port =
-		to_vf610_gp(irq_data_get_irq_chip_data(d));
+		gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	u8 irqc;
 
 	switch (type) {
@@ -182,7 +177,7 @@
 static void vf610_gpio_irq_mask(struct irq_data *d)
 {
 	struct vf610_gpio_port *port =
-		to_vf610_gp(irq_data_get_irq_chip_data(d));
+		gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	void __iomem *pcr_base = port->base + PORT_PCR(d->hwirq);
 
 	vf610_gpio_writel(0, pcr_base);
@@ -191,7 +186,7 @@
 static void vf610_gpio_irq_unmask(struct irq_data *d)
 {
 	struct vf610_gpio_port *port =
-		to_vf610_gp(irq_data_get_irq_chip_data(d));
+		gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	void __iomem *pcr_base = port->base + PORT_PCR(d->hwirq);
 
 	vf610_gpio_writel(port->irqc[d->hwirq] << PORT_PCR_IRQC_OFFSET,
@@ -201,7 +196,7 @@
 static int vf610_gpio_irq_set_wake(struct irq_data *d, u32 enable)
 {
 	struct vf610_gpio_port *port =
-		to_vf610_gp(irq_data_get_irq_chip_data(d));
+		gpiochip_get_data(irq_data_get_irq_chip_data(d));
 
 	if (enable)
 		enable_irq_wake(port->irq);
@@ -249,7 +244,7 @@
 
 	gc = &port->gc;
 	gc->of_node = np;
-	gc->dev = dev;
+	gc->parent = dev;
 	gc->label = "vf610-gpio";
 	gc->ngpio = VF610_GPIO_PER_PORT;
 	gc->base = of_alias_get_id(np, "gpio") * VF610_GPIO_PER_PORT;
@@ -261,7 +256,7 @@
 	gc->direction_output = vf610_gpio_direction_output;
 	gc->set = vf610_gpio_set;
 
-	ret = gpiochip_add(gc);
+	ret = gpiochip_add_data(gc, port);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c
index e2a11f2..1170b03 100644
--- a/drivers/gpio/gpio-viperboard.c
+++ b/drivers/gpio/gpio-viperboard.c
@@ -88,14 +88,13 @@
 		unsigned offset)
 {
 	int ret, answer, error = 0;
-	struct vprbrd_gpio *gpio =
-			container_of(chip, struct vprbrd_gpio, gpioa);
+	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
 	struct vprbrd *vb = gpio->vb;
 	struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
 
 	/* if io is set to output, just return the saved value */
 	if (gpio->gpioa_out & (1 << offset))
-		return gpio->gpioa_val & (1 << offset);
+		return !!(gpio->gpioa_val & (1 << offset));
 
 	mutex_lock(&vb->lock);
 
@@ -139,8 +138,7 @@
 		unsigned offset, int value)
 {
 	int ret;
-	struct vprbrd_gpio *gpio =
-			container_of(chip, struct vprbrd_gpio, gpioa);
+	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
 	struct vprbrd *vb = gpio->vb;
 	struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
 
@@ -173,7 +171,7 @@
 		mutex_unlock(&vb->lock);
 
 		if (ret != sizeof(struct vprbrd_gpioa_msg))
-			dev_err(chip->dev, "usb error setting pin value\n");
+			dev_err(chip->parent, "usb error setting pin value\n");
 	}
 }
 
@@ -181,8 +179,7 @@
 			unsigned offset)
 {
 	int ret;
-	struct vprbrd_gpio *gpio =
-			container_of(chip, struct vprbrd_gpio, gpioa);
+	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
 	struct vprbrd *vb = gpio->vb;
 	struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
 
@@ -219,8 +216,7 @@
 			unsigned offset, int value)
 {
 	int ret;
-	struct vprbrd_gpio *gpio =
-			container_of(chip, struct vprbrd_gpio, gpioa);
+	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
 	struct vprbrd *vb = gpio->vb;
 	struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
 
@@ -287,8 +283,7 @@
 {
 	int ret;
 	u16 val;
-	struct vprbrd_gpio *gpio =
-			container_of(chip, struct vprbrd_gpio, gpiob);
+	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
 	struct vprbrd *vb = gpio->vb;
 	struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;
 
@@ -319,8 +314,7 @@
 		unsigned offset, int value)
 {
 	int ret;
-	struct vprbrd_gpio *gpio =
-			container_of(chip, struct vprbrd_gpio, gpiob);
+	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
 	struct vprbrd *vb = gpio->vb;
 	struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;
 
@@ -345,7 +339,7 @@
 		mutex_unlock(&vb->lock);
 
 		if (ret != sizeof(struct vprbrd_gpiob_msg))
-			dev_err(chip->dev, "usb error setting pin value\n");
+			dev_err(chip->parent, "usb error setting pin value\n");
 	}
 }
 
@@ -353,8 +347,7 @@
 			unsigned offset)
 {
 	int ret;
-	struct vprbrd_gpio *gpio =
-			container_of(chip, struct vprbrd_gpio, gpiob);
+	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
 	struct vprbrd *vb = gpio->vb;
 
 	gpio->gpiob_out &= ~(1 << offset);
@@ -366,7 +359,7 @@
 	mutex_unlock(&vb->lock);
 
 	if (ret)
-		dev_err(chip->dev, "usb error setting pin to input\n");
+		dev_err(chip->parent, "usb error setting pin to input\n");
 
 	return ret;
 }
@@ -375,8 +368,7 @@
 			unsigned offset, int value)
 {
 	int ret;
-	struct vprbrd_gpio *gpio =
-			container_of(chip, struct vprbrd_gpio, gpiob);
+	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
 	struct vprbrd *vb = gpio->vb;
 
 	gpio->gpiob_out |= (1 << offset);
@@ -385,7 +377,7 @@
 
 	ret = vprbrd_gpiob_setdir(vb, offset, 1);
 	if (ret)
-		dev_err(chip->dev, "usb error setting pin to output\n");
+		dev_err(chip->parent, "usb error setting pin to output\n");
 
 	mutex_unlock(&vb->lock);
 
@@ -409,7 +401,7 @@
 	vb_gpio->vb = vb;
 	/* registering gpio a */
 	vb_gpio->gpioa.label = "viperboard gpio a";
-	vb_gpio->gpioa.dev = &pdev->dev;
+	vb_gpio->gpioa.parent = &pdev->dev;
 	vb_gpio->gpioa.owner = THIS_MODULE;
 	vb_gpio->gpioa.base = -1;
 	vb_gpio->gpioa.ngpio = 16;
@@ -418,15 +410,15 @@
 	vb_gpio->gpioa.get = vprbrd_gpioa_get;
 	vb_gpio->gpioa.direction_input = vprbrd_gpioa_direction_input;
 	vb_gpio->gpioa.direction_output = vprbrd_gpioa_direction_output;
-	ret = gpiochip_add(&vb_gpio->gpioa);
+	ret = gpiochip_add_data(&vb_gpio->gpioa, vb_gpio);
 	if (ret < 0) {
-		dev_err(vb_gpio->gpioa.dev, "could not add gpio a");
+		dev_err(vb_gpio->gpioa.parent, "could not add gpio a");
 		goto err_gpioa;
 	}
 
 	/* registering gpio b */
 	vb_gpio->gpiob.label = "viperboard gpio b";
-	vb_gpio->gpiob.dev = &pdev->dev;
+	vb_gpio->gpiob.parent = &pdev->dev;
 	vb_gpio->gpiob.owner = THIS_MODULE;
 	vb_gpio->gpiob.base = -1;
 	vb_gpio->gpiob.ngpio = 16;
@@ -435,9 +427,9 @@
 	vb_gpio->gpiob.get = vprbrd_gpiob_get;
 	vb_gpio->gpiob.direction_input = vprbrd_gpiob_direction_input;
 	vb_gpio->gpiob.direction_output = vprbrd_gpiob_direction_output;
-	ret = gpiochip_add(&vb_gpio->gpiob);
+	ret = gpiochip_add_data(&vb_gpio->gpiob, vb_gpio);
 	if (ret < 0) {
-		dev_err(vb_gpio->gpiob.dev, "could not add gpio b");
+		dev_err(vb_gpio->gpiob.parent, "could not add gpio b");
 		goto err_gpiob;
 	}
 
diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c
index c1caa45..ac8deb0 100644
--- a/drivers/gpio/gpio-vr41xx.c
+++ b/drivers/gpio/gpio-vr41xx.c
@@ -139,7 +139,7 @@
 static unsigned int startup_giuint(struct irq_data *data)
 {
 	if (gpiochip_lock_as_irq(&vr41xx_gpio_chip, data->hwirq))
-		dev_err(vr41xx_gpio_chip.dev,
+		dev_err(vr41xx_gpio_chip.parent,
 			"unable to lock HW IRQ %lu for IRQ\n",
 			data->hwirq);
 	/* Satisfy the .enable semantics by unmasking the line */
@@ -542,9 +542,9 @@
 	if (!giu_base)
 		return -ENOMEM;
 
-	vr41xx_gpio_chip.dev = &pdev->dev;
+	vr41xx_gpio_chip.parent = &pdev->dev;
 
-	ret = gpiochip_add(&vr41xx_gpio_chip);
+	ret = gpiochip_add_data(&vr41xx_gpio_chip, NULL);
 	if (!ret) {
 		iounmap(giu_base);
 		return -ENODEV;
diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c
index 57b470d..764999c 100644
--- a/drivers/gpio/gpio-vx855.c
+++ b/drivers/gpio/gpio-vx855.c
@@ -96,7 +96,7 @@
 static int vx855gpio_direction_input(struct gpio_chip *gpio,
 				     unsigned int nr)
 {
-	struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio);
+	struct vx855_gpio *vg = gpiochip_get_data(gpio);
 	unsigned long flags;
 	u_int32_t reg_out;
 
@@ -120,7 +120,7 @@
 
 static int vx855gpio_get(struct gpio_chip *gpio, unsigned int nr)
 {
-	struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio);
+	struct vx855_gpio *vg = gpiochip_get_data(gpio);
 	u_int32_t reg_in;
 	int ret = 0;
 
@@ -146,7 +146,7 @@
 static void vx855gpio_set(struct gpio_chip *gpio, unsigned int nr,
 			  int val)
 {
-	struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio);
+	struct vx855_gpio *vg = gpiochip_get_data(gpio);
 	unsigned long flags;
 	u_int32_t reg_out;
 
@@ -259,7 +259,7 @@
 
 	vx855gpio_gpio_setup(vg);
 
-	return gpiochip_add(&vg->gpio);
+	return gpiochip_add_data(&vg->gpio, vg);
 }
 
 static int vx855gpio_remove(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c
index 58ce75c..9839007 100644
--- a/drivers/gpio/gpio-wm831x.c
+++ b/drivers/gpio/gpio-wm831x.c
@@ -30,14 +30,9 @@
 	struct gpio_chip gpio_chip;
 };
 
-static inline struct wm831x_gpio *to_wm831x_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct wm831x_gpio, gpio_chip);
-}
-
 static int wm831x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
-	struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+	struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
 	struct wm831x *wm831x = wm831x_gpio->wm831x;
 	int val = WM831X_GPN_DIR;
 
@@ -51,7 +46,7 @@
 
 static int wm831x_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+	struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
 	struct wm831x *wm831x = wm831x_gpio->wm831x;
 	int ret;
 
@@ -67,7 +62,7 @@
 
 static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+	struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
 	struct wm831x *wm831x = wm831x_gpio->wm831x;
 
 	wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << offset,
@@ -77,7 +72,7 @@
 static int wm831x_gpio_direction_out(struct gpio_chip *chip,
 				     unsigned offset, int value)
 {
-	struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+	struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
 	struct wm831x *wm831x = wm831x_gpio->wm831x;
 	int val = 0;
 	int ret;
@@ -99,7 +94,7 @@
 
 static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+	struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
 	struct wm831x *wm831x = wm831x_gpio->wm831x;
 
 	return irq_create_mapping(wm831x->irq_domain,
@@ -109,7 +104,7 @@
 static int wm831x_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
 				    unsigned debounce)
 {
-	struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+	struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
 	struct wm831x *wm831x = wm831x_gpio->wm831x;
 	int reg = WM831X_GPIO1_CONTROL + offset;
 	int ret, fn;
@@ -140,7 +135,7 @@
 #ifdef CONFIG_DEBUG_FS
 static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
-	struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+	struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
 	struct wm831x *wm831x = wm831x_gpio->wm831x;
 	int i, tristated;
 
@@ -258,13 +253,13 @@
 	wm831x_gpio->wm831x = wm831x;
 	wm831x_gpio->gpio_chip = template_chip;
 	wm831x_gpio->gpio_chip.ngpio = wm831x->num_gpio;
-	wm831x_gpio->gpio_chip.dev = &pdev->dev;
+	wm831x_gpio->gpio_chip.parent = &pdev->dev;
 	if (pdata && pdata->gpio_base)
 		wm831x_gpio->gpio_chip.base = pdata->gpio_base;
 	else
 		wm831x_gpio->gpio_chip.base = -1;
 
-	ret = gpiochip_add(&wm831x_gpio->gpio_chip);
+	ret = gpiochip_add_data(&wm831x_gpio->gpio_chip, wm831x_gpio);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
 		return ret;
diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c
index 060b893..0a306b4 100644
--- a/drivers/gpio/gpio-wm8350.c
+++ b/drivers/gpio/gpio-wm8350.c
@@ -28,14 +28,9 @@
 	struct gpio_chip gpio_chip;
 };
 
-static inline struct wm8350_gpio_data *to_wm8350_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct wm8350_gpio_data, gpio_chip);
-}
-
 static int wm8350_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
-	struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip);
+	struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip);
 	struct wm8350 *wm8350 = wm8350_gpio->wm8350;
 
 	return wm8350_set_bits(wm8350, WM8350_GPIO_CONFIGURATION_I_O,
@@ -44,7 +39,7 @@
 
 static int wm8350_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip);
+	struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip);
 	struct wm8350 *wm8350 = wm8350_gpio->wm8350;
 	int ret;
 
@@ -60,7 +55,7 @@
 
 static void wm8350_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip);
+	struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip);
 	struct wm8350 *wm8350 = wm8350_gpio->wm8350;
 
 	if (value)
@@ -72,7 +67,7 @@
 static int wm8350_gpio_direction_out(struct gpio_chip *chip,
 				     unsigned offset, int value)
 {
-	struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip);
+	struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip);
 	struct wm8350 *wm8350 = wm8350_gpio->wm8350;
 	int ret;
 
@@ -89,7 +84,7 @@
 
 static int wm8350_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip);
+	struct wm8350_gpio_data *wm8350_gpio = gpiochip_get_data(chip);
 	struct wm8350 *wm8350 = wm8350_gpio->wm8350;
 
 	if (!wm8350->irq_base)
@@ -124,13 +119,13 @@
 	wm8350_gpio->wm8350 = wm8350;
 	wm8350_gpio->gpio_chip = template_chip;
 	wm8350_gpio->gpio_chip.ngpio = 13;
-	wm8350_gpio->gpio_chip.dev = &pdev->dev;
+	wm8350_gpio->gpio_chip.parent = &pdev->dev;
 	if (pdata && pdata->gpio_base)
 		wm8350_gpio->gpio_chip.base = pdata->gpio_base;
 	else
 		wm8350_gpio->gpio_chip.base = -1;
 
-	ret = gpiochip_add(&wm8350_gpio->gpio_chip);
+	ret = gpiochip_add_data(&wm8350_gpio->gpio_chip, wm8350_gpio);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
 		return ret;
diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c
index 6f5e42d..3ae4c15 100644
--- a/drivers/gpio/gpio-wm8994.c
+++ b/drivers/gpio/gpio-wm8994.c
@@ -31,14 +31,9 @@
 	struct gpio_chip gpio_chip;
 };
 
-static inline struct wm8994_gpio *to_wm8994_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct wm8994_gpio, gpio_chip);
-}
-
 static int wm8994_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
-	struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+	struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
 	struct wm8994 *wm8994 = wm8994_gpio->wm8994;
 
 	switch (wm8994->type) {
@@ -61,7 +56,7 @@
 
 static int wm8994_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
-	struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+	struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
 	struct wm8994 *wm8994 = wm8994_gpio->wm8994;
 
 	return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
@@ -70,7 +65,7 @@
 
 static int wm8994_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+	struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
 	struct wm8994 *wm8994 = wm8994_gpio->wm8994;
 	int ret;
 
@@ -87,7 +82,7 @@
 static int wm8994_gpio_direction_out(struct gpio_chip *chip,
 				     unsigned offset, int value)
 {
-	struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+	struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
 	struct wm8994 *wm8994 = wm8994_gpio->wm8994;
 
 	if (value)
@@ -99,7 +94,7 @@
 
 static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+	struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
 	struct wm8994 *wm8994 = wm8994_gpio->wm8994;
 
 	if (value)
@@ -110,7 +105,7 @@
 
 static int wm8994_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+	struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
 	struct wm8994 *wm8994 = wm8994_gpio->wm8994;
 
 	return regmap_irq_get_virq(wm8994->irq_data, offset);
@@ -174,7 +169,7 @@
 
 static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
-	struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+	struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
 	struct wm8994 *wm8994 = wm8994_gpio->wm8994;
 	int i;
 
@@ -260,13 +255,13 @@
 	wm8994_gpio->wm8994 = wm8994;
 	wm8994_gpio->gpio_chip = template_chip;
 	wm8994_gpio->gpio_chip.ngpio = WM8994_GPIO_MAX;
-	wm8994_gpio->gpio_chip.dev = &pdev->dev;
+	wm8994_gpio->gpio_chip.parent = &pdev->dev;
 	if (pdata && pdata->gpio_base)
 		wm8994_gpio->gpio_chip.base = pdata->gpio_base;
 	else
 		wm8994_gpio->gpio_chip.base = -1;
 
-	ret = gpiochip_add(&wm8994_gpio->gpio_chip);
+	ret = gpiochip_add_data(&wm8994_gpio->gpio_chip, wm8994_gpio);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
 			ret);
diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c
index d57068b..282004d 100644
--- a/drivers/gpio/gpio-xgene-sb.c
+++ b/drivers/gpio/gpio-xgene-sb.c
@@ -23,10 +23,8 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/of_gpio.h>
-#include <linux/gpio.h>
 #include <linux/gpio/driver.h>
 #include <linux/acpi.h>
-#include <linux/basic_mmio_gpio.h>
 
 #include "gpiolib.h"
 
@@ -43,38 +41,31 @@
 
 /**
  * struct xgene_gpio_sb - GPIO-Standby private data structure.
- * @bgc:			memory-mapped GPIO controllers.
+ * @gc:				memory-mapped GPIO controllers.
  * @irq:			Mapping GPIO pins and interrupt number
  * nirq:			Number of GPIO pins that supports interrupt
  */
 struct xgene_gpio_sb {
-	struct bgpio_chip	bgc;
+	struct gpio_chip	gc;
 	u32 *irq;
 	u32 nirq;
 };
 
-static inline struct xgene_gpio_sb *to_xgene_gpio_sb(struct gpio_chip *gc)
-{
-	struct bgpio_chip *bgc = to_bgpio_chip(gc);
-
-	return container_of(bgc, struct xgene_gpio_sb, bgc);
-}
-
-static void xgene_gpio_set_bit(struct bgpio_chip *bgc, void __iomem *reg, u32 gpio, int val)
+static void xgene_gpio_set_bit(struct gpio_chip *gc, void __iomem *reg, u32 gpio, int val)
 {
 	u32 data;
 
-	data = bgc->read_reg(reg);
+	data = gc->read_reg(reg);
 	if (val)
 		data |= GPIO_MASK(gpio);
 	else
 		data &= ~GPIO_MASK(gpio);
-	bgc->write_reg(reg, data);
+	gc->write_reg(reg, data);
 }
 
 static int apm_gpio_sb_to_irq(struct gpio_chip *gc, u32 gpio)
 {
-	struct xgene_gpio_sb *priv = to_xgene_gpio_sb(gc);
+	struct xgene_gpio_sb *priv = gpiochip_get_data(gc);
 
 	if (priv->irq[gpio])
 		return priv->irq[gpio];
@@ -99,15 +90,15 @@
 	if (IS_ERR(regs))
 		return PTR_ERR(regs);
 
-	ret = bgpio_init(&priv->bgc, &pdev->dev, 4,
+	ret = bgpio_init(&priv->gc, &pdev->dev, 4,
 			regs + MPA_GPIO_IN_ADDR,
 			regs + MPA_GPIO_OUT_ADDR, NULL,
 			regs + MPA_GPIO_OE_ADDR, NULL, 0);
         if (ret)
                 return ret;
 
-	priv->bgc.gc.to_irq = apm_gpio_sb_to_irq;
-	priv->bgc.gc.ngpio = XGENE_MAX_GPIO_DS;
+	priv->gc.to_irq = apm_gpio_sb_to_irq;
+	priv->gc.ngpio = XGENE_MAX_GPIO_DS;
 
 	priv->nirq = XGENE_MAX_GPIO_DS_IRQ;
 
@@ -118,14 +109,14 @@
 
 	for (i = 0; i < priv->nirq; i++) {
 		priv->irq[default_lines[i]] = platform_get_irq(pdev, i);
-		xgene_gpio_set_bit(&priv->bgc, regs + MPA_GPIO_SEL_LO,
+		xgene_gpio_set_bit(&priv->gc, regs + MPA_GPIO_SEL_LO,
                                    default_lines[i] * 2, 1);
-		xgene_gpio_set_bit(&priv->bgc, regs + MPA_GPIO_INT_LVL, i, 1);
+		xgene_gpio_set_bit(&priv->gc, regs + MPA_GPIO_INT_LVL, i, 1);
 	}
 
 	platform_set_drvdata(pdev, priv);
 
-	ret = gpiochip_add(&priv->bgc.gc);
+	ret = gpiochip_add_data(&priv->gc, priv);
 	if (ret)
 		dev_err(&pdev->dev, "failed to register X-Gene GPIO Standby driver\n");
 	else
@@ -133,7 +124,7 @@
 
 	if (priv->nirq > 0) {
 		/* Register interrupt handlers for gpio signaled acpi events */
-		acpi_gpiochip_request_interrupts(&priv->bgc.gc);
+		acpi_gpiochip_request_interrupts(&priv->gc);
 	}
 
 	return ret;
@@ -144,10 +135,11 @@
 	struct xgene_gpio_sb *priv = platform_get_drvdata(pdev);
 
 	if (priv->nirq > 0) {
-		acpi_gpiochip_free_interrupts(&priv->bgc.gc);
+		acpi_gpiochip_free_interrupts(&priv->gc);
 	}
 
-	return bgpio_remove(&priv->bgc);
+	gpiochip_remove(&priv->gc);
+	return 0;
 }
 
 static const struct of_device_id xgene_gpio_sb_of_match[] = {
diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c
index 18a8182..592e9cd 100644
--- a/drivers/gpio/gpio-xgene.c
+++ b/drivers/gpio/gpio-xgene.c
@@ -47,14 +47,9 @@
 #endif
 };
 
-static inline struct xgene_gpio *to_xgene_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct xgene_gpio, chip);
-}
-
 static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset)
 {
-	struct xgene_gpio *chip = to_xgene_gpio(gc);
+	struct xgene_gpio *chip = gpiochip_get_data(gc);
 	unsigned long bank_offset;
 	u32 bit_offset;
 
@@ -65,7 +60,7 @@
 
 static void __xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
 {
-	struct xgene_gpio *chip = to_xgene_gpio(gc);
+	struct xgene_gpio *chip = gpiochip_get_data(gc);
 	unsigned long bank_offset;
 	u32 setval, bit_offset;
 
@@ -82,7 +77,7 @@
 
 static void xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
 {
-	struct xgene_gpio *chip = to_xgene_gpio(gc);
+	struct xgene_gpio *chip = gpiochip_get_data(gc);
 	unsigned long flags;
 
 	spin_lock_irqsave(&chip->lock, flags);
@@ -92,7 +87,7 @@
 
 static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
 {
-	struct xgene_gpio *chip = to_xgene_gpio(gc);
+	struct xgene_gpio *chip = gpiochip_get_data(gc);
 	unsigned long flags, bank_offset;
 	u32 dirval, bit_offset;
 
@@ -113,7 +108,7 @@
 static int xgene_gpio_dir_out(struct gpio_chip *gc,
 					unsigned int offset, int val)
 {
-	struct xgene_gpio *chip = to_xgene_gpio(gc);
+	struct xgene_gpio *chip = gpiochip_get_data(gc);
 	unsigned long flags, bank_offset;
 	u32 dirval, bit_offset;
 
@@ -188,7 +183,7 @@
 	gpio->chip.ngpio = XGENE_MAX_GPIOS;
 
 	spin_lock_init(&gpio->lock);
-	gpio->chip.dev = &pdev->dev;
+	gpio->chip.parent = &pdev->dev;
 	gpio->chip.direction_input = xgene_gpio_dir_in;
 	gpio->chip.direction_output = xgene_gpio_dir_out;
 	gpio->chip.get = xgene_gpio_get;
@@ -198,7 +193,7 @@
 
 	platform_set_drvdata(pdev, gpio);
 
-	err = gpiochip_add(&gpio->chip);
+	err = gpiochip_add_data(&gpio->chip, gpio);
 	if (err) {
 		dev_err(&pdev->dev,
 			"failed to register gpiochip.\n");
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index d5284df..d0fbb7f 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -92,8 +92,7 @@
 static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
 {
 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-	struct xgpio_instance *chip =
-	    container_of(mm_gc, struct xgpio_instance, mmchip);
+	struct xgpio_instance *chip = gpiochip_get_data(gc);
 	u32 val;
 
 	val = xgpio_readreg(mm_gc->regs + XGPIO_DATA_OFFSET +
@@ -115,8 +114,7 @@
 {
 	unsigned long flags;
 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-	struct xgpio_instance *chip =
-	    container_of(mm_gc, struct xgpio_instance, mmchip);
+	struct xgpio_instance *chip = gpiochip_get_data(gc);
 	int index =  xgpio_index(chip, gpio);
 	int offset =  xgpio_offset(chip, gpio);
 
@@ -147,8 +145,7 @@
 {
 	unsigned long flags;
 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-	struct xgpio_instance *chip =
-	    container_of(mm_gc, struct xgpio_instance, mmchip);
+	struct xgpio_instance *chip = gpiochip_get_data(gc);
 	int index =  xgpio_index(chip, gpio);
 	int offset =  xgpio_offset(chip, gpio);
 
@@ -180,8 +177,7 @@
 {
 	unsigned long flags;
 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-	struct xgpio_instance *chip =
-	    container_of(mm_gc, struct xgpio_instance, mmchip);
+	struct xgpio_instance *chip = gpiochip_get_data(gc);
 	int index =  xgpio_index(chip, gpio);
 	int offset =  xgpio_offset(chip, gpio);
 
@@ -212,7 +208,7 @@
 static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
 {
 	struct xgpio_instance *chip =
-	    container_of(mm_gc, struct xgpio_instance, mmchip);
+		container_of(mm_gc, struct xgpio_instance, mmchip);
 
 	xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET,	chip->gpio_state[0]);
 	xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]);
@@ -305,7 +301,7 @@
 	}
 
 	chip->mmchip.gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1];
-	chip->mmchip.gc.dev = &pdev->dev;
+	chip->mmchip.gc.parent = &pdev->dev;
 	chip->mmchip.gc.direction_input = xgpio_dir_in;
 	chip->mmchip.gc.direction_output = xgpio_dir_out;
 	chip->mmchip.gc.get = xgpio_get;
@@ -314,7 +310,7 @@
 	chip->mmchip.save_regs = xgpio_save_regs;
 
 	/* Call the OF gpio helper to setup and register the GPIO device */
-	status = of_mm_gpiochip_add(np, &chip->mmchip);
+	status = of_mm_gpiochip_add_data(np, &chip->mmchip, chip);
 	if (status) {
 		pr_err("%s: error in probe function with status %d\n",
 		       np->full_name, status);
diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c
index bc06a2c..aa5813d 100644
--- a/drivers/gpio/gpio-xlp.c
+++ b/drivers/gpio/gpio-xlp.c
@@ -100,11 +100,6 @@
 	spinlock_t lock;
 };
 
-static struct xlp_gpio_priv *gpio_chip_to_xlp_priv(struct gpio_chip *gc)
-{
-	return container_of(gc, struct xlp_gpio_priv, chip);
-}
-
 static int xlp_gpio_get_reg(void __iomem *addr, unsigned gpio)
 {
 	u32 pos, regset;
@@ -133,7 +128,7 @@
 static void xlp_gpio_irq_disable(struct irq_data *d)
 {
 	struct gpio_chip *gc  = irq_data_get_irq_chip_data(d);
-	struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
@@ -145,7 +140,7 @@
 static void xlp_gpio_irq_mask_ack(struct irq_data *d)
 {
 	struct gpio_chip *gc  = irq_data_get_irq_chip_data(d);
-	struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
@@ -158,7 +153,7 @@
 static void xlp_gpio_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc  = irq_data_get_irq_chip_data(d);
-	struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
@@ -170,7 +165,7 @@
 static int xlp_gpio_set_irq_type(struct irq_data *d, unsigned int type)
 {
 	struct gpio_chip *gc  = irq_data_get_irq_chip_data(d);
-	struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
 	int pol, irq_type;
 
 	switch (type) {
@@ -235,7 +230,7 @@
 
 static int xlp_gpio_dir_output(struct gpio_chip *gc, unsigned gpio, int state)
 {
-	struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
 
 	BUG_ON(gpio >= gc->ngpio);
 	xlp_gpio_set_reg(priv->gpio_out_en, gpio, 0x1);
@@ -245,7 +240,7 @@
 
 static int xlp_gpio_dir_input(struct gpio_chip *gc, unsigned gpio)
 {
-	struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
 
 	BUG_ON(gpio >= gc->ngpio);
 	xlp_gpio_set_reg(priv->gpio_out_en, gpio, 0x0);
@@ -255,7 +250,7 @@
 
 static int xlp_gpio_get(struct gpio_chip *gc, unsigned gpio)
 {
-	struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
 
 	BUG_ON(gpio >= gc->ngpio);
 	return xlp_gpio_get_reg(priv->gpio_paddrv, gpio);
@@ -263,7 +258,7 @@
 
 static void xlp_gpio_set(struct gpio_chip *gc, unsigned gpio, int state)
 {
-	struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
 
 	BUG_ON(gpio >= gc->ngpio);
 	xlp_gpio_set_reg(priv->gpio_paddrv, gpio, state);
@@ -373,7 +368,7 @@
 	gc->owner = THIS_MODULE;
 	gc->label = dev_name(&pdev->dev);
 	gc->base = 0;
-	gc->dev = &pdev->dev;
+	gc->parent = &pdev->dev;
 	gc->ngpio = ngpio;
 	gc->of_node = pdev->dev.of_node;
 	gc->direction_output = xlp_gpio_dir_output;
@@ -388,7 +383,7 @@
 		return -ENODEV;
 	}
 
-	err = gpiochip_add(gc);
+	err = gpiochip_add_data(gc, priv);
 	if (err < 0)
 		goto out_free_desc;
 
diff --git a/drivers/gpio/gpio-xtensa.c b/drivers/gpio/gpio-xtensa.c
index 93ec95d..f16c042 100644
--- a/drivers/gpio/gpio-xtensa.c
+++ b/drivers/gpio/gpio-xtensa.c
@@ -148,10 +148,10 @@
 {
 	int ret;
 
-	ret = gpiochip_add(&impwire_chip);
+	ret = gpiochip_add_data(&impwire_chip, NULL);
 	if (ret)
 		return ret;
-	return gpiochip_add(&expstate_chip);
+	return gpiochip_add_data(&expstate_chip, NULL);
 }
 
 static struct platform_driver xtensa_gpio_driver = {
diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c
index 6f02d7c..cda6d92 100644
--- a/drivers/gpio/gpio-zevio.c
+++ b/drivers/gpio/gpio-zevio.c
@@ -52,9 +52,6 @@
 #define ZEVIO_GPIO_INPUT			0x18
 #define ZEVIO_GPIO_INT_STICKY		0x20
 
-#define to_zevio_gpio(chip) container_of(to_of_mm_gpio_chip(chip), \
-				struct zevio_gpio, chip)
-
 /* Bit number of GPIO in its section */
 #define ZEVIO_GPIO_BIT(gpio) (gpio&7)
 
@@ -80,7 +77,7 @@
 /* Functions for struct gpio_chip */
 static int zevio_gpio_get(struct gpio_chip *chip, unsigned pin)
 {
-	struct zevio_gpio *controller = to_zevio_gpio(chip);
+	struct zevio_gpio *controller = gpiochip_get_data(chip);
 	u32 val, dir;
 
 	spin_lock(&controller->lock);
@@ -96,7 +93,7 @@
 
 static void zevio_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
 {
-	struct zevio_gpio *controller = to_zevio_gpio(chip);
+	struct zevio_gpio *controller = gpiochip_get_data(chip);
 	u32 val;
 
 	spin_lock(&controller->lock);
@@ -112,7 +109,7 @@
 
 static int zevio_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
 {
-	struct zevio_gpio *controller = to_zevio_gpio(chip);
+	struct zevio_gpio *controller = gpiochip_get_data(chip);
 	u32 val;
 
 	spin_lock(&controller->lock);
@@ -129,7 +126,7 @@
 static int zevio_gpio_direction_output(struct gpio_chip *chip,
 				       unsigned pin, int value)
 {
-	struct zevio_gpio *controller = to_zevio_gpio(chip);
+	struct zevio_gpio *controller = gpiochip_get_data(chip);
 	u32 val;
 
 	spin_lock(&controller->lock);
@@ -185,9 +182,11 @@
 
 	/* Copy our reference */
 	controller->chip.gc = zevio_gpio_chip;
-	controller->chip.gc.dev = &pdev->dev;
+	controller->chip.gc.parent = &pdev->dev;
 
-	status = of_mm_gpiochip_add(pdev->dev.of_node, &(controller->chip));
+	status = of_mm_gpiochip_add_data(pdev->dev.of_node,
+					 &(controller->chip),
+					 controller);
 	if (status) {
 		dev_err(&pdev->dev, "failed to add gpiochip: %d\n", status);
 		return status;
@@ -199,7 +198,7 @@
 	for (i = 0; i < controller->chip.gc.ngpio; i += 8)
 		zevio_gpio_port_set(controller, i, ZEVIO_GPIO_INT_MASK, 0xFF);
 
-	dev_dbg(controller->chip.gc.dev, "ZEVIO GPIO controller set up!\n");
+	dev_dbg(controller->chip.gc.parent, "ZEVIO GPIO controller set up!\n");
 
 	return 0;
 }
diff --git a/drivers/gpio/gpio-zx.c b/drivers/gpio/gpio-zx.c
index 1dcf7a6..47c79fa 100644
--- a/drivers/gpio/gpio-zx.c
+++ b/drivers/gpio/gpio-zx.c
@@ -43,14 +43,9 @@
 	struct gpio_chip	gc;
 };
 
-static inline struct zx_gpio *to_zx(struct gpio_chip *gc)
-{
-	return container_of(gc, struct zx_gpio, gc);
-}
-
 static int zx_direction_input(struct gpio_chip *gc, unsigned offset)
 {
-	struct zx_gpio *chip = to_zx(gc);
+	struct zx_gpio *chip = gpiochip_get_data(gc);
 	unsigned long flags;
 	u16 gpiodir;
 
@@ -69,7 +64,7 @@
 static int zx_direction_output(struct gpio_chip *gc, unsigned offset,
 		int value)
 {
-	struct zx_gpio *chip = to_zx(gc);
+	struct zx_gpio *chip = gpiochip_get_data(gc);
 	unsigned long flags;
 	u16 gpiodir;
 
@@ -92,14 +87,14 @@
 
 static int zx_get_value(struct gpio_chip *gc, unsigned offset)
 {
-	struct zx_gpio *chip = to_zx(gc);
+	struct zx_gpio *chip = gpiochip_get_data(gc);
 
 	return !!(readw_relaxed(chip->base + ZX_GPIO_DI) & BIT(offset));
 }
 
 static void zx_set_value(struct gpio_chip *gc, unsigned offset, int value)
 {
-	struct zx_gpio *chip = to_zx(gc);
+	struct zx_gpio *chip = gpiochip_get_data(gc);
 
 	if (value)
 		writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO1);
@@ -110,7 +105,7 @@
 static int zx_irq_type(struct irq_data *d, unsigned trigger)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct zx_gpio *chip = to_zx(gc);
+	struct zx_gpio *chip = gpiochip_get_data(gc);
 	int offset = irqd_to_hwirq(d);
 	unsigned long flags;
 	u16 gpiois, gpioi_epos, gpioi_eneg, gpioiev;
@@ -162,7 +157,7 @@
 	unsigned long pending;
 	int offset;
 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
-	struct zx_gpio *chip = to_zx(gc);
+	struct zx_gpio *chip = gpiochip_get_data(gc);
 	struct irq_chip *irqchip = irq_desc_get_chip(desc);
 
 	chained_irq_enter(irqchip, desc);
@@ -181,7 +176,7 @@
 static void zx_irq_mask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct zx_gpio *chip = to_zx(gc);
+	struct zx_gpio *chip = gpiochip_get_data(gc);
 	u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR);
 	u16 gpioie;
 
@@ -196,7 +191,7 @@
 static void zx_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct zx_gpio *chip = to_zx(gc);
+	struct zx_gpio *chip = gpiochip_get_data(gc);
 	u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR);
 	u16 gpioie;
 
@@ -245,10 +240,10 @@
 	chip->gc.base = ZX_GPIO_NR * id;
 	chip->gc.ngpio = ZX_GPIO_NR;
 	chip->gc.label = dev_name(dev);
-	chip->gc.dev = dev;
+	chip->gc.parent = dev;
 	chip->gc.owner = THIS_MODULE;
 
-	ret = gpiochip_add(&chip->gc);
+	ret = gpiochip_add_data(&chip->gc, chip);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 8abeaca..66d3d24 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -131,11 +131,6 @@
 static struct irq_chip zynq_gpio_level_irqchip;
 static struct irq_chip zynq_gpio_edge_irqchip;
 
-static struct zynq_gpio *to_zynq_gpio(struct gpio_chip *gc)
-{
-	return container_of(gc, struct zynq_gpio, chip);
-}
-
 /**
  * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank
  * for a given pin in the GPIO device
@@ -183,7 +178,7 @@
 {
 	u32 data;
 	unsigned int bank_num, bank_pin_num;
-	struct zynq_gpio *gpio = to_zynq_gpio(chip);
+	struct zynq_gpio *gpio = gpiochip_get_data(chip);
 
 	zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
 
@@ -207,7 +202,7 @@
 				int state)
 {
 	unsigned int reg_offset, bank_num, bank_pin_num;
-	struct zynq_gpio *gpio = to_zynq_gpio(chip);
+	struct zynq_gpio *gpio = gpiochip_get_data(chip);
 
 	zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
 
@@ -244,7 +239,7 @@
 {
 	u32 reg;
 	unsigned int bank_num, bank_pin_num;
-	struct zynq_gpio *gpio = to_zynq_gpio(chip);
+	struct zynq_gpio *gpio = gpiochip_get_data(chip);
 
 	zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
 
@@ -277,7 +272,7 @@
 {
 	u32 reg;
 	unsigned int bank_num, bank_pin_num;
-	struct zynq_gpio *gpio = to_zynq_gpio(chip);
+	struct zynq_gpio *gpio = gpiochip_get_data(chip);
 
 	zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
 
@@ -308,7 +303,7 @@
 {
 	unsigned int device_pin_num, bank_num, bank_pin_num;
 	struct zynq_gpio *gpio =
-		to_zynq_gpio(irq_data_get_irq_chip_data(irq_data));
+		gpiochip_get_data(irq_data_get_irq_chip_data(irq_data));
 
 	device_pin_num = irq_data->hwirq;
 	zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
@@ -329,7 +324,7 @@
 {
 	unsigned int device_pin_num, bank_num, bank_pin_num;
 	struct zynq_gpio *gpio =
-		to_zynq_gpio(irq_data_get_irq_chip_data(irq_data));
+		gpiochip_get_data(irq_data_get_irq_chip_data(irq_data));
 
 	device_pin_num = irq_data->hwirq;
 	zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
@@ -349,7 +344,7 @@
 {
 	unsigned int device_pin_num, bank_num, bank_pin_num;
 	struct zynq_gpio *gpio =
-		to_zynq_gpio(irq_data_get_irq_chip_data(irq_data));
+		gpiochip_get_data(irq_data_get_irq_chip_data(irq_data));
 
 	device_pin_num = irq_data->hwirq;
 	zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
@@ -400,7 +395,7 @@
 	u32 int_type, int_pol, int_any;
 	unsigned int device_pin_num, bank_num, bank_pin_num;
 	struct zynq_gpio *gpio =
-		to_zynq_gpio(irq_data_get_irq_chip_data(irq_data));
+		gpiochip_get_data(irq_data_get_irq_chip_data(irq_data));
 
 	device_pin_num = irq_data->hwirq;
 	zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
@@ -464,7 +459,7 @@
 static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on)
 {
 	struct zynq_gpio *gpio =
-		to_zynq_gpio(irq_data_get_irq_chip_data(data));
+		gpiochip_get_data(irq_data_get_irq_chip_data(data));
 
 	irq_set_irq_wake(gpio->irq, on);
 
@@ -530,7 +525,7 @@
 	u32 int_sts, int_enb;
 	unsigned int bank_num;
 	struct zynq_gpio *gpio =
-		to_zynq_gpio(irq_desc_get_handler_data(desc));
+		gpiochip_get_data(irq_desc_get_handler_data(desc));
 	struct irq_chip *irqchip = irq_desc_get_chip(desc);
 
 	chained_irq_enter(irqchip, desc);
@@ -592,7 +587,7 @@
 {
 	int ret;
 
-	ret = pm_runtime_get_sync(chip->dev);
+	ret = pm_runtime_get_sync(chip->parent);
 
 	/*
 	 * If the device is already active pm_runtime_get() will return 1 on
@@ -603,7 +598,7 @@
 
 static void zynq_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
-	pm_runtime_put(chip->dev);
+	pm_runtime_put(chip->parent);
 }
 
 static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
@@ -698,7 +693,7 @@
 	chip = &gpio->chip;
 	chip->label = gpio->p_data->label;
 	chip->owner = THIS_MODULE;
-	chip->dev = &pdev->dev;
+	chip->parent = &pdev->dev;
 	chip->get = zynq_gpio_get_value;
 	chip->set = zynq_gpio_set_value;
 	chip->request = zynq_gpio_request;
@@ -708,23 +703,23 @@
 	chip->base = -1;
 	chip->ngpio = gpio->p_data->ngpio;
 
-	/* Enable GPIO clock */
+	/* Retrieve GPIO clock */
 	gpio->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(gpio->clk)) {
 		dev_err(&pdev->dev, "input clock not found.\n");
 		return PTR_ERR(gpio->clk);
 	}
-	ret = clk_prepare_enable(gpio->clk);
-	if (ret) {
-		dev_err(&pdev->dev, "Unable to enable clock.\n");
+
+	pm_runtime_enable(&pdev->dev);
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret < 0)
 		return ret;
-	}
 
 	/* report a bug if gpio chip registration fails */
-	ret = gpiochip_add(chip);
+	ret = gpiochip_add_data(chip, gpio);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to add gpio chip\n");
-		goto err_disable_clk;
+		goto err_pm_put;
 	}
 
 	/* disable interrupts for all banks */
@@ -742,15 +737,14 @@
 	gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, gpio->irq,
 				     zynq_gpio_irqhandler);
 
-	pm_runtime_set_active(&pdev->dev);
-	pm_runtime_enable(&pdev->dev);
+	pm_runtime_put(&pdev->dev);
 
 	return 0;
 
 err_rm_gpiochip:
 	gpiochip_remove(chip);
-err_disable_clk:
-	clk_disable_unprepare(gpio->clk);
+err_pm_put:
+	pm_runtime_put(&pdev->dev);
 
 	return ret;
 }
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index bc34bc5..540cbc8 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -51,10 +51,10 @@
 
 static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
 {
-	if (!gc->dev)
+	if (!gc->parent)
 		return false;
 
-	return ACPI_HANDLE(gc->dev) == data;
+	return ACPI_HANDLE(gc->parent) == data;
 }
 
 #ifdef CONFIG_PINCTRL
@@ -184,7 +184,7 @@
 	if (agpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT)
 		return AE_OK;
 
-	handle = ACPI_HANDLE(chip->dev);
+	handle = ACPI_HANDLE(chip->parent);
 	pin = agpio->pin_table[0];
 
 	if (pin <= 255) {
@@ -208,7 +208,7 @@
 
 	desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event");
 	if (IS_ERR(desc)) {
-		dev_err(chip->dev, "Failed to request GPIO\n");
+		dev_err(chip->parent, "Failed to request GPIO\n");
 		return AE_ERROR;
 	}
 
@@ -216,13 +216,13 @@
 
 	ret = gpiochip_lock_as_irq(chip, pin);
 	if (ret) {
-		dev_err(chip->dev, "Failed to lock GPIO as interrupt\n");
+		dev_err(chip->parent, "Failed to lock GPIO as interrupt\n");
 		goto fail_free_desc;
 	}
 
 	irq = gpiod_to_irq(desc);
 	if (irq < 0) {
-		dev_err(chip->dev, "Failed to translate GPIO to IRQ\n");
+		dev_err(chip->parent, "Failed to translate GPIO to IRQ\n");
 		goto fail_unlock_irq;
 	}
 
@@ -259,7 +259,8 @@
 	ret = request_threaded_irq(event->irq, NULL, handler, irqflags,
 				   "ACPI:Event", event);
 	if (ret) {
-		dev_err(chip->dev, "Failed to setup interrupt handler for %d\n",
+		dev_err(chip->parent,
+			"Failed to setup interrupt handler for %d\n",
 			event->irq);
 		goto fail_free_event;
 	}
@@ -293,10 +294,10 @@
 	acpi_handle handle;
 	acpi_status status;
 
-	if (!chip->dev || !chip->to_irq)
+	if (!chip->parent || !chip->to_irq)
 		return;
 
-	handle = ACPI_HANDLE(chip->dev);
+	handle = ACPI_HANDLE(chip->parent);
 	if (!handle)
 		return;
 
@@ -323,10 +324,10 @@
 	acpi_handle handle;
 	acpi_status status;
 
-	if (!chip->dev || !chip->to_irq)
+	if (!chip->parent || !chip->to_irq)
 		return;
 
-	handle = ACPI_HANDLE(chip->dev);
+	handle = ACPI_HANDLE(chip->parent);
 	if (!handle)
 		return;
 
@@ -769,7 +770,7 @@
 static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip)
 {
 	struct gpio_chip *chip = achip->chip;
-	acpi_handle handle = ACPI_HANDLE(chip->dev);
+	acpi_handle handle = ACPI_HANDLE(chip->parent);
 	acpi_status status;
 
 	INIT_LIST_HEAD(&achip->conns);
@@ -778,20 +779,22 @@
 						    acpi_gpio_adr_space_handler,
 						    NULL, achip);
 	if (ACPI_FAILURE(status))
-		dev_err(chip->dev, "Failed to install GPIO OpRegion handler\n");
+		dev_err(chip->parent,
+		        "Failed to install GPIO OpRegion handler\n");
 }
 
 static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
 {
 	struct gpio_chip *chip = achip->chip;
-	acpi_handle handle = ACPI_HANDLE(chip->dev);
+	acpi_handle handle = ACPI_HANDLE(chip->parent);
 	struct acpi_gpio_connection *conn, *tmp;
 	acpi_status status;
 
 	status = acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GPIO,
 						   acpi_gpio_adr_space_handler);
 	if (ACPI_FAILURE(status)) {
-		dev_err(chip->dev, "Failed to remove GPIO OpRegion handler\n");
+		dev_err(chip->parent,
+			"Failed to remove GPIO OpRegion handler\n");
 		return;
 	}
 
@@ -808,16 +811,16 @@
 	acpi_handle handle;
 	acpi_status status;
 
-	if (!chip || !chip->dev)
+	if (!chip || !chip->parent)
 		return;
 
-	handle = ACPI_HANDLE(chip->dev);
+	handle = ACPI_HANDLE(chip->parent);
 	if (!handle)
 		return;
 
 	acpi_gpio = kzalloc(sizeof(*acpi_gpio), GFP_KERNEL);
 	if (!acpi_gpio) {
-		dev_err(chip->dev,
+		dev_err(chip->parent,
 			"Failed to allocate memory for ACPI GPIO chip\n");
 		return;
 	}
@@ -827,7 +830,7 @@
 
 	status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio);
 	if (ACPI_FAILURE(status)) {
-		dev_err(chip->dev, "Failed to attach ACPI GPIO chip\n");
+		dev_err(chip->parent, "Failed to attach ACPI GPIO chip\n");
 		kfree(acpi_gpio);
 		return;
 	}
@@ -841,16 +844,16 @@
 	acpi_handle handle;
 	acpi_status status;
 
-	if (!chip || !chip->dev)
+	if (!chip || !chip->parent)
 		return;
 
-	handle = ACPI_HANDLE(chip->dev);
+	handle = ACPI_HANDLE(chip->parent);
 	if (!handle)
 		return;
 
 	status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
 	if (ACPI_FAILURE(status)) {
-		dev_warn(chip->dev, "Failed to retrieve ACPI GPIO chip\n");
+		dev_warn(chip->parent, "Failed to retrieve ACPI GPIO chip\n");
 		return;
 	}
 
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 5fe34a9..42a4bb7 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -262,9 +262,10 @@
 EXPORT_SYMBOL(of_gpio_simple_xlate);
 
 /**
- * of_mm_gpiochip_add - Add memory mapped GPIO chip (bank)
+ * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
  * @np:		device node of the GPIO chip
  * @mm_gc:	pointer to the of_mm_gpio_chip allocated structure
+ * @data:	driver data to store in the struct gpio_chip
  *
  * To use this function you should allocate and fill mm_gc with:
  *
@@ -280,8 +281,9 @@
  * do all necessary work for you. Then you'll able to use .regs
  * to manage GPIOs from the callbacks.
  */
-int of_mm_gpiochip_add(struct device_node *np,
-		       struct of_mm_gpio_chip *mm_gc)
+int of_mm_gpiochip_add_data(struct device_node *np,
+			    struct of_mm_gpio_chip *mm_gc,
+			    void *data)
 {
 	int ret = -ENOMEM;
 	struct gpio_chip *gc = &mm_gc->gc;
@@ -301,7 +303,7 @@
 
 	mm_gc->gc.of_node = np;
 
-	ret = gpiochip_add(gc);
+	ret = gpiochip_add_data(gc, data);
 	if (ret)
 		goto err2;
 
@@ -315,7 +317,7 @@
 	       np->full_name, ret);
 	return ret;
 }
-EXPORT_SYMBOL(of_mm_gpiochip_add);
+EXPORT_SYMBOL(of_mm_gpiochip_add_data);
 
 /**
  * of_mm_gpiochip_remove - Remove memory mapped GPIO chip (bank)
@@ -423,8 +425,8 @@
 {
 	int status;
 
-	if ((!chip->of_node) && (chip->dev))
-		chip->of_node = chip->dev->of_node;
+	if ((!chip->of_node) && (chip->parent))
+		chip->of_node = chip->parent->of_node;
 
 	if (!chip->of_node)
 		return 0;
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index b57ed8e..405dfca 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -605,7 +605,7 @@
 	if (chip->names && chip->names[offset])
 		ioname = chip->names[offset];
 
-	dev = device_create_with_groups(&gpio_class, chip->dev,
+	dev = device_create_with_groups(&gpio_class, chip->parent,
 					MKDEV(0, 0), data, gpio_groups,
 					ioname ? ioname : "gpio%u",
 					desc_to_gpio(desc));
@@ -730,7 +730,8 @@
 		return 0;
 
 	/* use chip->base for the ID; it's already known to be unique */
-	dev = device_create_with_groups(&gpio_class, chip->dev, MKDEV(0, 0),
+	dev = device_create_with_groups(&gpio_class, chip->parent,
+					MKDEV(0, 0),
 					chip, gpiochip_groups,
 					"gpiochip%d", chip->base);
 	if (IS_ERR(dev))
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 3346abd..5c1ba87 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -182,39 +182,62 @@
 
 /*
  * Add a new chip to the global chips list, keeping the list of chips sorted
- * by base order.
+ * by range(means [base, base + ngpio - 1]) order.
  *
  * Return -EBUSY if the new chip overlaps with some other chip's integer
  * space.
  */
 static int gpiochip_add_to_list(struct gpio_chip *chip)
 {
-	struct list_head *pos;
-	struct gpio_chip *_chip;
-	int err = 0;
+	struct gpio_chip *iterator;
+	struct gpio_chip *previous = NULL;
 
-	/* find where to insert our chip */
-	list_for_each(pos, &gpio_chips) {
-		_chip = list_entry(pos, struct gpio_chip, list);
-		/* shall we insert before _chip? */
-		if (_chip->base >= chip->base + chip->ngpio)
-			break;
+	if (list_empty(&gpio_chips)) {
+		list_add_tail(&chip->list, &gpio_chips);
+		return 0;
 	}
 
-	/* are we stepping on the chip right before? */
-	if (pos != &gpio_chips && pos->prev != &gpio_chips) {
-		_chip = list_entry(pos->prev, struct gpio_chip, list);
-		if (_chip->base + _chip->ngpio > chip->base) {
-			dev_err(chip->dev,
-			       "GPIO integer space overlap, cannot add chip\n");
-			err = -EBUSY;
+	list_for_each_entry(iterator, &gpio_chips, list) {
+		if (iterator->base >= chip->base + chip->ngpio) {
+			/*
+			 * Iterator is the first GPIO chip so there is no
+			 * previous one
+			 */
+			if (!previous) {
+				goto found;
+			} else {
+				/*
+				 * We found a valid range(means
+				 * [base, base + ngpio - 1]) between previous
+				 * and iterator chip.
+				 */
+				if (previous->base + previous->ngpio
+						<= chip->base)
+					goto found;
+			}
 		}
+		previous = iterator;
 	}
 
-	if (!err)
-		list_add_tail(&chip->list, pos);
+	/*
+	 * We are beyond the last chip in the list and iterator now
+	 * points to the head.
+	 * Let iterator point to the last chip in the list.
+	 */
 
-	return err;
+	iterator = list_last_entry(&gpio_chips, struct gpio_chip, list);
+	if (iterator->base + iterator->ngpio <= chip->base) {
+		list_add(&chip->list, &iterator->list);
+		return 0;
+	}
+
+	dev_err(chip->parent,
+	       "GPIO integer space overlap, cannot add chip\n");
+	return -EBUSY;
+
+found:
+	list_add_tail(&chip->list, &iterator->list);
+	return 0;
 }
 
 /**
@@ -252,7 +275,7 @@
  * Takes the names from gc->names and checks if they are all unique. If they
  * are, they are assigned to their gpio descriptors.
  *
- * Returns -EEXIST if one of the names is already used for a different GPIO.
+ * Warning if one of the names is already used for a different GPIO.
  */
 static int gpiochip_set_desc_names(struct gpio_chip *gc)
 {
@@ -267,7 +290,7 @@
 
 		gpio = gpio_name_to_desc(gc->names[i]);
 		if (gpio)
-			dev_warn(gc->dev, "Detected name collision for "
+			dev_warn(gc->parent, "Detected name collision for "
 				 "GPIO name '%s'\n",
 				 gc->names[i]);
 	}
@@ -280,7 +303,7 @@
 }
 
 /**
- * gpiochip_add() - register a gpio_chip
+ * gpiochip_add_data() - register a gpio_chip
  * @chip: the chip to register, with chip->base initialized
  * Context: potentially before irqs will work
  *
@@ -288,15 +311,15 @@
  * because the chip->base is invalid or already associated with a
  * different chip.  Otherwise it returns zero as a success code.
  *
- * When gpiochip_add() is called very early during boot, so that GPIOs
- * can be freely used, the chip->dev device must be registered before
+ * When gpiochip_add_data() is called very early during boot, so that GPIOs
+ * can be freely used, the chip->parent device must be registered before
  * the gpio framework's arch_initcall().  Otherwise sysfs initialization
  * for GPIOs will fail rudely.
  *
  * If chip->base is negative, this requests dynamic assignment of
  * a range of valid GPIOs.
  */
-int gpiochip_add(struct gpio_chip *chip)
+int gpiochip_add_data(struct gpio_chip *chip, void *data)
 {
 	unsigned long	flags;
 	int		status = 0;
@@ -308,6 +331,13 @@
 	if (!descs)
 		return -ENOMEM;
 
+	chip->data = data;
+
+	if (chip->ngpio == 0) {
+		chip_err(chip, "tried to insert a GPIO chip with zero lines\n");
+		return -EINVAL;
+	}
+
 	spin_lock_irqsave(&gpio_lock, flags);
 
 	if (base < 0) {
@@ -348,8 +378,8 @@
 	INIT_LIST_HEAD(&chip->pin_ranges);
 #endif
 
-	if (!chip->owner && chip->dev && chip->dev->driver)
-		chip->owner = chip->dev->driver->owner;
+	if (!chip->owner && chip->parent && chip->parent->driver)
+		chip->owner = chip->parent->driver->owner;
 
 	status = gpiochip_set_desc_names(chip);
 	if (status)
@@ -389,7 +419,7 @@
 		chip->label ? : "generic");
 	return status;
 }
-EXPORT_SYMBOL_GPL(gpiochip_add);
+EXPORT_SYMBOL_GPL(gpiochip_add_data);
 
 /**
  * gpiochip_remove() - unregister a gpio_chip
@@ -424,7 +454,8 @@
 	spin_unlock_irqrestore(&gpio_lock, flags);
 
 	if (requested)
-		dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
+		dev_crit(chip->parent,
+			 "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
 
 	kfree(chip->desc);
 	chip->desc = NULL;
@@ -659,7 +690,7 @@
  * gpiochip, providing an irq domain to translate the local IRQs to
  * global irqs in the gpiolib core, and making sure that the gpiochip
  * is passed as chip data to all related functions. Driver callbacks
- * need to use container_of() to get their local state containers back
+ * need to use gpiochip_get_data() to get their local state containers back
  * from the gpiochip passed as chip data. An irqdomain will be stored
  * in the gpiochip that shall be used by the driver to handle IRQ number
  * translation. The gpiochip will need to be initialized and registered
@@ -683,15 +714,16 @@
 	if (!gpiochip || !irqchip)
 		return -EINVAL;
 
-	if (!gpiochip->dev) {
+	if (!gpiochip->parent) {
 		pr_err("missing gpiochip .dev parent pointer\n");
 		return -EINVAL;
 	}
-	of_node = gpiochip->dev->of_node;
+	of_node = gpiochip->parent->of_node;
 #ifdef CONFIG_OF_GPIO
 	/*
 	 * If the gpiochip has an assigned OF node this takes precedence
-	 * FIXME: get rid of this and use gpiochip->dev->of_node everywhere
+	 * FIXME: get rid of this and use gpiochip->parent->of_node
+	 * everywhere
 	 */
 	if (gpiochip->of_node)
 		of_node = gpiochip->of_node;
@@ -1279,13 +1311,7 @@
 	chip = desc->chip;
 	offset = gpio_chip_hwgpio(desc);
 	value = chip->get ? chip->get(chip, offset) : -EIO;
-	/*
-	 * FIXME: fix all drivers to clamp to [0,1] or return negative,
-	 * then change this to:
-	 * value = value < 0 ? value : !!value;
-	 * so we can properly propagate error codes.
-	 */
-	value = !!value;
+	value = value < 0 ? value : !!value;
 	trace_gpio_value(desc_to_gpio(desc), 1, value);
 	return value;
 }
@@ -2512,7 +2538,7 @@
 
 	seq_printf(s, "%sGPIOs %d-%d", (char *)s->private,
 			chip->base, chip->base + chip->ngpio - 1);
-	dev = chip->dev;
+	dev = chip->parent;
 	if (dev)
 		seq_printf(s, ", %s/%s", dev->bus ? dev->bus->name : "no-bus",
 			dev_name(dev));
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index be3a977..99ed3b0 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -16,7 +16,7 @@
 #include <linux/device.h>
 
 enum of_gpio_flags;
-
+enum gpiod_flags;
 struct acpi_device;
 
 /**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
index 5580d34..acd066d0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -518,7 +518,7 @@
 int
 amdgpu_framebuffer_init(struct drm_device *dev,
 			struct amdgpu_framebuffer *rfb,
-			struct drm_mode_fb_cmd2 *mode_cmd,
+			const struct drm_mode_fb_cmd2 *mode_cmd,
 			struct drm_gem_object *obj)
 {
 	int ret;
@@ -535,7 +535,7 @@
 static struct drm_framebuffer *
 amdgpu_user_framebuffer_create(struct drm_device *dev,
 			       struct drm_file *file_priv,
-			       struct drm_mode_fb_cmd2 *mode_cmd)
+			       const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct drm_gem_object *obj;
 	struct amdgpu_framebuffer *amdgpu_fb;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
index 093a8c6..6fcbbcc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
@@ -45,7 +45,6 @@
 struct amdgpu_fbdev {
 	struct drm_fb_helper helper;
 	struct amdgpu_framebuffer rfb;
-	struct list_head fbdev_list;
 	struct amdgpu_device *adev;
 };
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index 064ebb3..a53d756 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -556,7 +556,7 @@
 
 int amdgpu_framebuffer_init(struct drm_device *dev,
 			     struct amdgpu_framebuffer *rfb,
-			     struct drm_mode_fb_cmd2 *mode_cmd,
+			     const struct drm_mode_fb_cmd2 *mode_cmd,
 			     struct drm_gem_object *obj);
 
 int amdgpufb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
diff --git a/drivers/gpu/drm/armada/armada_fb.c b/drivers/gpu/drm/armada/armada_fb.c
index 1c90969..5fa4bf2 100644
--- a/drivers/gpu/drm/armada/armada_fb.c
+++ b/drivers/gpu/drm/armada/armada_fb.c
@@ -35,7 +35,7 @@
 };
 
 struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev,
-	struct drm_mode_fb_cmd2 *mode, struct armada_gem_object *obj)
+	const struct drm_mode_fb_cmd2 *mode, struct armada_gem_object *obj)
 {
 	struct armada_framebuffer *dfb;
 	uint8_t format, config;
@@ -101,7 +101,7 @@
 }
 
 static struct drm_framebuffer *armada_fb_create(struct drm_device *dev,
-	struct drm_file *dfile, struct drm_mode_fb_cmd2 *mode)
+	struct drm_file *dfile, const struct drm_mode_fb_cmd2 *mode)
 {
 	struct armada_gem_object *obj;
 	struct armada_framebuffer *dfb;
diff --git a/drivers/gpu/drm/armada/armada_fb.h b/drivers/gpu/drm/armada/armada_fb.h
index ce3f12e..48073c4 100644
--- a/drivers/gpu/drm/armada/armada_fb.h
+++ b/drivers/gpu/drm/armada/armada_fb.h
@@ -19,6 +19,6 @@
 #define drm_fb_obj(fb) drm_fb_to_armada_fb(fb)->obj
 
 struct armada_framebuffer *armada_framebuffer_create(struct drm_device *,
-	struct drm_mode_fb_cmd2 *, struct armada_gem_object *);
+	const struct drm_mode_fb_cmd2 *, struct armada_gem_object *);
 
 #endif
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index 05f6522..eb57159 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -256,7 +256,6 @@
 struct ast_fbdev {
 	struct drm_fb_helper helper;
 	struct ast_framebuffer afb;
-	struct list_head fbdev_list;
 	void *sysram;
 	int size;
 	struct ttm_bo_kmap_obj mapping;
@@ -309,7 +308,7 @@
 
 int ast_framebuffer_init(struct drm_device *dev,
 			 struct ast_framebuffer *ast_fb,
-			 struct drm_mode_fb_cmd2 *mode_cmd,
+			 const struct drm_mode_fb_cmd2 *mode_cmd,
 			 struct drm_gem_object *obj);
 
 int ast_fbdev_init(struct drm_device *dev);
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c
index a37e7ea..5320f8c 100644
--- a/drivers/gpu/drm/ast/ast_fb.c
+++ b/drivers/gpu/drm/ast/ast_fb.c
@@ -163,7 +163,7 @@
 };
 
 static int astfb_create_object(struct ast_fbdev *afbdev,
-			       struct drm_mode_fb_cmd2 *mode_cmd,
+			       const struct drm_mode_fb_cmd2 *mode_cmd,
 			       struct drm_gem_object **gobj_p)
 {
 	struct drm_device *dev = afbdev->helper.dev;
diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
index 541a610..9759009 100644
--- a/drivers/gpu/drm/ast/ast_main.c
+++ b/drivers/gpu/drm/ast/ast_main.c
@@ -309,7 +309,7 @@
 
 int ast_framebuffer_init(struct drm_device *dev,
 			 struct ast_framebuffer *ast_fb,
-			 struct drm_mode_fb_cmd2 *mode_cmd,
+			 const struct drm_mode_fb_cmd2 *mode_cmd,
 			 struct drm_gem_object *obj)
 {
 	int ret;
@@ -327,7 +327,7 @@
 static struct drm_framebuffer *
 ast_user_framebuffer_create(struct drm_device *dev,
 	       struct drm_file *filp,
-	       struct drm_mode_fb_cmd2 *mode_cmd)
+	       const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct drm_gem_object *obj;
 	struct ast_framebuffer *ast_fb;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index 244df0a..8168954 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -402,7 +402,7 @@
 }
 
 static struct drm_framebuffer *atmel_hlcdc_fb_create(struct drm_device *dev,
-		struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd)
+		struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	return drm_fb_cma_create(dev, file_priv, mode_cmd);
 }
diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h
index 71f2687..19b5ada 100644
--- a/drivers/gpu/drm/bochs/bochs.h
+++ b/drivers/gpu/drm/bochs/bochs.h
@@ -149,7 +149,7 @@
 
 int bochs_framebuffer_init(struct drm_device *dev,
 			   struct bochs_framebuffer *gfb,
-			   struct drm_mode_fb_cmd2 *mode_cmd,
+			   const struct drm_mode_fb_cmd2 *mode_cmd,
 			   struct drm_gem_object *obj);
 int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr);
 int bochs_bo_unpin(struct bochs_bo *bo);
diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c
index 09a0637..7520bf8 100644
--- a/drivers/gpu/drm/bochs/bochs_fbdev.c
+++ b/drivers/gpu/drm/bochs/bochs_fbdev.c
@@ -34,7 +34,7 @@
 };
 
 static int bochsfb_create_object(struct bochs_device *bochs,
-				 struct drm_mode_fb_cmd2 *mode_cmd,
+				 const struct drm_mode_fb_cmd2 *mode_cmd,
 				 struct drm_gem_object **gobj_p)
 {
 	struct drm_device *dev = bochs->dev;
diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c
index f69e6bf..d812ad0 100644
--- a/drivers/gpu/drm/bochs/bochs_mm.c
+++ b/drivers/gpu/drm/bochs/bochs_mm.c
@@ -484,7 +484,7 @@
 
 int bochs_framebuffer_init(struct drm_device *dev,
 			   struct bochs_framebuffer *gfb,
-			   struct drm_mode_fb_cmd2 *mode_cmd,
+			   const struct drm_mode_fb_cmd2 *mode_cmd,
 			   struct drm_gem_object *obj)
 {
 	int ret;
@@ -502,7 +502,7 @@
 static struct drm_framebuffer *
 bochs_user_framebuffer_create(struct drm_device *dev,
 			      struct drm_file *filp,
-			      struct drm_mode_fb_cmd2 *mode_cmd)
+			      const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct drm_gem_object *obj;
 	struct bochs_framebuffer *bochs_fb;
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h
index 7050615..b774d63 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.h
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.h
@@ -153,7 +153,6 @@
 struct cirrus_fbdev {
 	struct drm_fb_helper helper;
 	struct cirrus_framebuffer gfb;
-	struct list_head fbdev_list;
 	void *sysram;
 	int size;
 	int x1, y1, x2, y2; /* dirty rect */
@@ -207,7 +206,7 @@
 
 int cirrus_framebuffer_init(struct drm_device *dev,
 			   struct cirrus_framebuffer *gfb,
-			    struct drm_mode_fb_cmd2 *mode_cmd,
+			    const struct drm_mode_fb_cmd2 *mode_cmd,
 			    struct drm_gem_object *obj);
 
 bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height,
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
index 589103b..3b5be72 100644
--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
+++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
@@ -135,7 +135,7 @@
 };
 
 static int cirrusfb_create_object(struct cirrus_fbdev *afbdev,
-			       struct drm_mode_fb_cmd2 *mode_cmd,
+			       const struct drm_mode_fb_cmd2 *mode_cmd,
 			       struct drm_gem_object **gobj_p)
 {
 	struct drm_device *dev = afbdev->helper.dev;
diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c
index 055fd86..0907715 100644
--- a/drivers/gpu/drm/cirrus/cirrus_main.c
+++ b/drivers/gpu/drm/cirrus/cirrus_main.c
@@ -29,7 +29,7 @@
 
 int cirrus_framebuffer_init(struct drm_device *dev,
 			    struct cirrus_framebuffer *gfb,
-			    struct drm_mode_fb_cmd2 *mode_cmd,
+			    const struct drm_mode_fb_cmd2 *mode_cmd,
 			    struct drm_gem_object *obj)
 {
 	int ret;
@@ -47,7 +47,7 @@
 static struct drm_framebuffer *
 cirrus_user_framebuffer_create(struct drm_device *dev,
 			       struct drm_file *filp,
-			       struct drm_mode_fb_cmd2 *mode_cmd)
+			       const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct cirrus_device *cdev = dev->dev_private;
 	struct drm_gem_object *obj;
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index aeee083..ef5f766 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -316,8 +316,7 @@
 	if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0)
 		return 0;
 
-	if (state->mode_blob)
-		drm_property_unreference_blob(state->mode_blob);
+	drm_property_unreference_blob(state->mode_blob);
 	state->mode_blob = NULL;
 
 	if (mode) {
@@ -363,8 +362,7 @@
 	if (blob == state->mode_blob)
 		return 0;
 
-	if (state->mode_blob)
-		drm_property_unreference_blob(state->mode_blob);
+	drm_property_unreference_blob(state->mode_blob);
 	state->mode_blob = NULL;
 
 	if (blob) {
@@ -419,8 +417,7 @@
 		struct drm_property_blob *mode =
 			drm_property_lookup_blob(dev, val);
 		ret = drm_atomic_set_mode_prop_for_crtc(state, mode);
-		if (mode)
-			drm_property_unreference_blob(mode);
+		drm_property_unreference_blob(mode);
 		return ret;
 	}
 	else if (crtc->funcs->atomic_set_property)
@@ -1191,12 +1188,7 @@
 retry:
 	drm_modeset_backoff(state->acquire_ctx);
 
-	ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
-			       state->acquire_ctx);
-	if (ret)
-		goto retry;
-	ret = drm_modeset_lock_all_crtcs(state->dev,
-					 state->acquire_ctx);
+	ret = drm_modeset_lock_all_ctx(state->dev, state->acquire_ctx);
 	if (ret)
 		goto retry;
 }
@@ -1433,7 +1425,7 @@
 }
 
 /**
- * drm_atomic_update_old_fb -- Unset old_fb pointers and set plane->fb pointers.
+ * drm_atomic_clean_old_fb -- Unset old_fb pointers and set plane->fb pointers.
  *
  * @dev: drm device to check.
  * @plane_mask: plane mask for planes that were updated.
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index e5aec45..74a5fc4 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -80,6 +80,27 @@
 	}
 }
 
+static bool
+check_pending_encoder_assignment(struct drm_atomic_state *state,
+				 struct drm_encoder *new_encoder,
+				 struct drm_connector *new_connector)
+{
+	struct drm_connector *connector;
+	struct drm_connector_state *conn_state;
+	int i;
+
+	for_each_connector_in_state(state, connector, conn_state, i) {
+		if (conn_state->best_encoder != new_encoder)
+			continue;
+
+		/* encoder already assigned and we're trying to re-steal it! */
+		if (connector->state->best_encoder != conn_state->best_encoder)
+			return false;
+	}
+
+	return true;
+}
+
 static struct drm_crtc *
 get_current_crtc_for_encoder(struct drm_device *dev,
 			     struct drm_encoder *encoder)
@@ -229,6 +250,13 @@
 		return 0;
 	}
 
+	if (!check_pending_encoder_assignment(state, new_encoder, connector)) {
+		DRM_DEBUG_ATOMIC("Encoder for [CONNECTOR:%d:%s] already assigned\n",
+				 connector->base.id,
+				 connector->name);
+		return -EINVAL;
+	}
+
 	encoder_crtc = get_current_crtc_for_encoder(state->dev,
 						    new_encoder);
 
@@ -1342,6 +1370,49 @@
 EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc);
 
 /**
+ * drm_atomic_helper_disable_planes_on_crtc - helper to disable CRTC's planes
+ * @crtc: CRTC
+ * @atomic: if set, synchronize with CRTC's atomic_begin/flush hooks
+ *
+ * Disables all planes associated with the given CRTC. This can be
+ * used for instance in the CRTC helper disable callback to disable
+ * all planes before shutting down the display pipeline.
+ *
+ * If the atomic-parameter is set the function calls the CRTC's
+ * atomic_begin hook before and atomic_flush hook after disabling the
+ * planes.
+ *
+ * It is a bug to call this function without having implemented the
+ * ->atomic_disable() plane hook.
+ */
+void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc,
+					      bool atomic)
+{
+	const struct drm_crtc_helper_funcs *crtc_funcs =
+		crtc->helper_private;
+	struct drm_plane *plane;
+
+	if (atomic && crtc_funcs && crtc_funcs->atomic_begin)
+		crtc_funcs->atomic_begin(crtc, NULL);
+
+	drm_for_each_plane(plane, crtc->dev) {
+		const struct drm_plane_helper_funcs *plane_funcs =
+			plane->helper_private;
+
+		if (plane->state->crtc != crtc || !plane_funcs)
+			continue;
+
+		WARN_ON(!plane_funcs->atomic_disable);
+		if (plane_funcs->atomic_disable)
+			plane_funcs->atomic_disable(plane, NULL);
+	}
+
+	if (atomic && crtc_funcs && crtc_funcs->atomic_flush)
+		crtc_funcs->atomic_flush(crtc, NULL);
+}
+EXPORT_SYMBOL(drm_atomic_helper_disable_planes_on_crtc);
+
+/**
  * drm_atomic_helper_cleanup_planes - cleanup plane resources after commit
  * @dev: DRM device
  * @old_state: atomic state object with old state structures
@@ -1485,12 +1556,12 @@
 	drm_atomic_set_fb_for_plane(plane_state, fb);
 	plane_state->crtc_x = crtc_x;
 	plane_state->crtc_y = crtc_y;
-	plane_state->crtc_h = crtc_h;
 	plane_state->crtc_w = crtc_w;
+	plane_state->crtc_h = crtc_h;
 	plane_state->src_x = src_x;
 	plane_state->src_y = src_y;
-	plane_state->src_h = src_h;
 	plane_state->src_w = src_w;
+	plane_state->src_h = src_h;
 
 	if (plane == crtc->cursor)
 		state->legacy_cursor_update = true;
@@ -1609,12 +1680,12 @@
 	drm_atomic_set_fb_for_plane(plane_state, NULL);
 	plane_state->crtc_x = 0;
 	plane_state->crtc_y = 0;
-	plane_state->crtc_h = 0;
 	plane_state->crtc_w = 0;
+	plane_state->crtc_h = 0;
 	plane_state->src_x = 0;
 	plane_state->src_y = 0;
-	plane_state->src_h = 0;
 	plane_state->src_w = 0;
+	plane_state->src_h = 0;
 
 	return 0;
 }
@@ -1797,16 +1868,16 @@
 	drm_atomic_set_fb_for_plane(primary_state, set->fb);
 	primary_state->crtc_x = 0;
 	primary_state->crtc_y = 0;
-	primary_state->crtc_h = vdisplay;
 	primary_state->crtc_w = hdisplay;
+	primary_state->crtc_h = vdisplay;
 	primary_state->src_x = set->x << 16;
 	primary_state->src_y = set->y << 16;
 	if (primary_state->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
-		primary_state->src_h = hdisplay << 16;
 		primary_state->src_w = vdisplay << 16;
+		primary_state->src_h = hdisplay << 16;
 	} else {
-		primary_state->src_h = vdisplay << 16;
 		primary_state->src_w = hdisplay << 16;
+		primary_state->src_h = vdisplay << 16;
 	}
 
 commit:
@@ -1818,6 +1889,161 @@
 }
 
 /**
+ * drm_atomic_helper_disable_all - disable all currently active outputs
+ * @dev: DRM device
+ * @ctx: lock acquisition context
+ *
+ * Loops through all connectors, finding those that aren't turned off and then
+ * turns them off by setting their DPMS mode to OFF and deactivating the CRTC
+ * that they are connected to.
+ *
+ * This is used for example in suspend/resume to disable all currently active
+ * functions when suspending.
+ *
+ * Note that if callers haven't already acquired all modeset locks this might
+ * return -EDEADLK, which must be handled by calling drm_modeset_backoff().
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ *
+ * See also:
+ * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
+ */
+int drm_atomic_helper_disable_all(struct drm_device *dev,
+				  struct drm_modeset_acquire_ctx *ctx)
+{
+	struct drm_atomic_state *state;
+	struct drm_connector *conn;
+	int err;
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = ctx;
+
+	drm_for_each_connector(conn, dev) {
+		struct drm_crtc *crtc = conn->state->crtc;
+		struct drm_crtc_state *crtc_state;
+
+		if (!crtc || conn->dpms != DRM_MODE_DPMS_ON)
+			continue;
+
+		crtc_state = drm_atomic_get_crtc_state(state, crtc);
+		if (IS_ERR(crtc_state)) {
+			err = PTR_ERR(crtc_state);
+			goto free;
+		}
+
+		crtc_state->active = false;
+	}
+
+	err = drm_atomic_commit(state);
+
+free:
+	if (err < 0)
+		drm_atomic_state_free(state);
+
+	return err;
+}
+EXPORT_SYMBOL(drm_atomic_helper_disable_all);
+
+/**
+ * drm_atomic_helper_suspend - subsystem-level suspend helper
+ * @dev: DRM device
+ *
+ * Duplicates the current atomic state, disables all active outputs and then
+ * returns a pointer to the original atomic state to the caller. Drivers can
+ * pass this pointer to the drm_atomic_helper_resume() helper upon resume to
+ * restore the output configuration that was active at the time the system
+ * entered suspend.
+ *
+ * Note that it is potentially unsafe to use this. The atomic state object
+ * returned by this function is assumed to be persistent. Drivers must ensure
+ * that this holds true. Before calling this function, drivers must make sure
+ * to suspend fbdev emulation so that nothing can be using the device.
+ *
+ * Returns:
+ * A pointer to a copy of the state before suspend on success or an ERR_PTR()-
+ * encoded error code on failure. Drivers should store the returned atomic
+ * state object and pass it to the drm_atomic_helper_resume() helper upon
+ * resume.
+ *
+ * See also:
+ * drm_atomic_helper_duplicate_state(), drm_atomic_helper_disable_all(),
+ * drm_atomic_helper_resume()
+ */
+struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev)
+{
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_atomic_state *state;
+	int err;
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+retry:
+	err = drm_modeset_lock_all_ctx(dev, &ctx);
+	if (err < 0) {
+		state = ERR_PTR(err);
+		goto unlock;
+	}
+
+	state = drm_atomic_helper_duplicate_state(dev, &ctx);
+	if (IS_ERR(state))
+		goto unlock;
+
+	err = drm_atomic_helper_disable_all(dev, &ctx);
+	if (err < 0) {
+		drm_atomic_state_free(state);
+		state = ERR_PTR(err);
+		goto unlock;
+	}
+
+unlock:
+	if (PTR_ERR(state) == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry;
+	}
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+	return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_suspend);
+
+/**
+ * drm_atomic_helper_resume - subsystem-level resume helper
+ * @dev: DRM device
+ * @state: atomic state to resume to
+ *
+ * Calls drm_mode_config_reset() to synchronize hardware and software states,
+ * grabs all modeset locks and commits the atomic state object. This can be
+ * used in conjunction with the drm_atomic_helper_suspend() helper to
+ * implement suspend/resume for drivers that support atomic mode-setting.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ *
+ * See also:
+ * drm_atomic_helper_suspend()
+ */
+int drm_atomic_helper_resume(struct drm_device *dev,
+			     struct drm_atomic_state *state)
+{
+	struct drm_mode_config *config = &dev->mode_config;
+	int err;
+
+	drm_mode_config_reset(dev);
+	drm_modeset_lock_all(dev);
+	state->acquire_ctx = config->acquire_ctx;
+	err = drm_atomic_commit(state);
+	drm_modeset_unlock_all(dev);
+
+	return err;
+}
+EXPORT_SYMBOL(drm_atomic_helper_resume);
+
+/**
  * drm_atomic_helper_crtc_set_property - helper for crtc properties
  * @crtc: DRM crtc
  * @property: DRM property
@@ -2184,7 +2410,7 @@
  */
 void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
 {
-	if (crtc->state && crtc->state->mode_blob)
+	if (crtc->state)
 		drm_property_unreference_blob(crtc->state->mode_blob);
 	kfree(crtc->state);
 	crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
@@ -2252,8 +2478,7 @@
 void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
 					    struct drm_crtc_state *state)
 {
-	if (state->mode_blob)
-		drm_property_unreference_blob(state->mode_blob);
+	drm_property_unreference_blob(state->mode_blob);
 }
 EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
 
@@ -2430,7 +2655,9 @@
  * @ctx: lock acquisition context
  *
  * Makes a copy of the current atomic state by looping over all objects and
- * duplicating their respective states.
+ * duplicating their respective states. This is used for example by suspend/
+ * resume support code to save the state prior to suspend such that it can
+ * be restored upon resume.
  *
  * Note that this treats atomic state as persistent between save and restore.
  * Drivers must make sure that this is possible and won't result in confusion
@@ -2442,6 +2669,9 @@
  * Returns:
  * A pointer to the copy of the atomic state object on success or an
  * ERR_PTR()-encoded error code on failure.
+ *
+ * See also:
+ * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
  */
 struct drm_atomic_state *
 drm_atomic_helper_duplicate_state(struct drm_device *dev,
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 24c5434..32dd134 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -45,7 +45,7 @@
 
 static struct drm_framebuffer *
 internal_framebuffer_create(struct drm_device *dev,
-			    struct drm_mode_fb_cmd2 *r,
+			    const struct drm_mode_fb_cmd2 *r,
 			    struct drm_file *file_priv);
 
 /* Avoid boilerplate.  I'm tired of typing. */
@@ -3235,7 +3235,7 @@
 
 static struct drm_framebuffer *
 internal_framebuffer_create(struct drm_device *dev,
-			    struct drm_mode_fb_cmd2 *r,
+			    const struct drm_mode_fb_cmd2 *r,
 			    struct drm_file *file_priv)
 {
 	struct drm_mode_config *config = &dev->mode_config;
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index ef53475..10d0989 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -818,7 +818,7 @@
  * metadata fields.
  */
 void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
-				    struct drm_mode_fb_cmd2 *mode_cmd)
+				    const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	int i;
 
@@ -855,6 +855,12 @@
  * due to slight differences in allocating shared resources when the
  * configuration is restored in a different order than when userspace set it up)
  * need to use their own restore logic.
+ *
+ * This function is deprecated. New drivers should implement atomic mode-
+ * setting and use the atomic suspend/resume helpers.
+ *
+ * See also:
+ * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
  */
 void drm_helper_resume_force_mode(struct drm_device *dev)
 {
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index d5d2c03..c214f12 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2545,6 +2545,33 @@
 	return clock;
 }
 
+static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_match,
+					     unsigned int clock_tolerance)
+{
+	u8 mode;
+
+	if (!to_match->clock)
+		return 0;
+
+	for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) {
+		const struct drm_display_mode *cea_mode = &edid_cea_modes[mode];
+		unsigned int clock1, clock2;
+
+		/* Check both 60Hz and 59.94Hz */
+		clock1 = cea_mode->clock;
+		clock2 = cea_mode_alternate_clock(cea_mode);
+
+		if (abs(to_match->clock - clock1) > clock_tolerance &&
+		    abs(to_match->clock - clock2) > clock_tolerance)
+			continue;
+
+		if (drm_mode_equal_no_clocks(to_match, cea_mode))
+			return mode + 1;
+	}
+
+	return 0;
+}
+
 /**
  * drm_match_cea_mode - look for a CEA mode matching given mode
  * @to_match: display mode
@@ -2609,6 +2636,33 @@
 	return cea_mode_alternate_clock(hdmi_mode);
 }
 
+static u8 drm_match_hdmi_mode_clock_tolerance(const struct drm_display_mode *to_match,
+					      unsigned int clock_tolerance)
+{
+	u8 mode;
+
+	if (!to_match->clock)
+		return 0;
+
+	for (mode = 0; mode < ARRAY_SIZE(edid_4k_modes); mode++) {
+		const struct drm_display_mode *hdmi_mode = &edid_4k_modes[mode];
+		unsigned int clock1, clock2;
+
+		/* Make sure to also match alternate clocks */
+		clock1 = hdmi_mode->clock;
+		clock2 = hdmi_mode_alternate_clock(hdmi_mode);
+
+		if (abs(to_match->clock - clock1) > clock_tolerance &&
+		    abs(to_match->clock - clock2) > clock_tolerance)
+			continue;
+
+		if (drm_mode_equal_no_clocks(to_match, hdmi_mode))
+			return mode + 1;
+	}
+
+	return 0;
+}
+
 /*
  * drm_match_hdmi_mode - look for a HDMI mode matching given mode
  * @to_match: display mode
@@ -3119,14 +3173,18 @@
 	u8 mode_idx;
 	const char *type;
 
-	mode_idx = drm_match_cea_mode(mode) - 1;
+	/*
+	 * allow 5kHz clock difference either way to account for
+	 * the 10kHz clock resolution limit of detailed timings.
+	 */
+	mode_idx = drm_match_cea_mode_clock_tolerance(mode, 5) - 1;
 	if (mode_idx < ARRAY_SIZE(edid_cea_modes)) {
 		type = "CEA";
 		cea_mode = &edid_cea_modes[mode_idx];
 		clock1 = cea_mode->clock;
 		clock2 = cea_mode_alternate_clock(cea_mode);
 	} else {
-		mode_idx = drm_match_hdmi_mode(mode) - 1;
+		mode_idx = drm_match_hdmi_mode_clock_tolerance(mode, 5) - 1;
 		if (mode_idx < ARRAY_SIZE(edid_4k_modes)) {
 			type = "HDMI";
 			cea_mode = &edid_4k_modes[mode_idx];
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index c19a625..b7d5b84 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -74,7 +74,7 @@
 };
 
 static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev,
-	struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_cma_object **obj,
+	const const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_cma_object **obj,
 	unsigned int num_planes)
 {
 	struct drm_fb_cma *fb_cma;
@@ -107,7 +107,7 @@
  * checked before calling this function.
  */
 struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev,
-	struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd)
+	struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct drm_fb_cma *fb_cma;
 	struct drm_gem_cma_object *objs[4];
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 6b5625e..1ea8790 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -226,6 +226,8 @@
 	init_waitqueue_head(&priv->event_wait);
 	priv->event_space = 4096; /* set aside 4k for event buffer */
 
+	mutex_init(&priv->event_read_lock);
+
 	if (drm_core_check_feature(dev, DRIVER_GEM))
 		drm_gem_open(dev, priv);
 
@@ -511,14 +513,28 @@
 {
 	struct drm_file *file_priv = filp->private_data;
 	struct drm_device *dev = file_priv->minor->dev;
-	ssize_t ret = 0;
+	ssize_t ret;
 
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
 
-	spin_lock_irq(&dev->event_lock);
+	ret = mutex_lock_interruptible(&file_priv->event_read_lock);
+	if (ret)
+		return ret;
+
 	for (;;) {
-		if (list_empty(&file_priv->event_list)) {
+		struct drm_pending_event *e = NULL;
+
+		spin_lock_irq(&dev->event_lock);
+		if (!list_empty(&file_priv->event_list)) {
+			e = list_first_entry(&file_priv->event_list,
+					struct drm_pending_event, link);
+			file_priv->event_space += e->event->length;
+			list_del(&e->link);
+		}
+		spin_unlock_irq(&dev->event_lock);
+
+		if (e == NULL) {
 			if (ret)
 				break;
 
@@ -527,36 +543,36 @@
 				break;
 			}
 
-			spin_unlock_irq(&dev->event_lock);
+			mutex_unlock(&file_priv->event_read_lock);
 			ret = wait_event_interruptible(file_priv->event_wait,
 						       !list_empty(&file_priv->event_list));
-			spin_lock_irq(&dev->event_lock);
-			if (ret < 0)
-				break;
-
-			ret = 0;
+			if (ret >= 0)
+				ret = mutex_lock_interruptible(&file_priv->event_read_lock);
+			if (ret)
+				return ret;
 		} else {
-			struct drm_pending_event *e;
+			unsigned length = e->event->length;
 
-			e = list_first_entry(&file_priv->event_list,
-					     struct drm_pending_event, link);
-			if (e->event->length + ret > count)
-				break;
-
-			if (__copy_to_user_inatomic(buffer + ret,
-						    e->event, e->event->length)) {
-				if (ret == 0)
-					ret = -EFAULT;
+			if (length > count - ret) {
+put_back_event:
+				spin_lock_irq(&dev->event_lock);
+				file_priv->event_space -= length;
+				list_add(&e->link, &file_priv->event_list);
+				spin_unlock_irq(&dev->event_lock);
 				break;
 			}
 
-			file_priv->event_space += e->event->length;
-			ret += e->event->length;
-			list_del(&e->link);
+			if (copy_to_user(buffer + ret, e->event, length)) {
+				if (ret == 0)
+					ret = -EFAULT;
+				goto put_back_event;
+			}
+
+			ret += length;
 			e->destroy(e);
 		}
 	}
-	spin_unlock_irq(&dev->event_lock);
+	mutex_unlock(&file_priv->event_read_lock);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index c7de454..2e10bba 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -244,8 +244,9 @@
  * @filp: drm file-private structure to use for the handle look up
  * @handle: userspace handle to delete
  *
- * Removes the GEM handle from the @filp lookup table and if this is the last
- * handle also cleans up linked resources like GEM names.
+ * Removes the GEM handle from the @filp lookup table which has been added with
+ * drm_gem_handle_create(). If this is the last handle also cleans up linked
+ * resources like GEM names.
  */
 int
 drm_gem_handle_delete(struct drm_file *filp, u32 handle)
@@ -314,6 +315,10 @@
  * This expects the dev->object_name_lock to be held already and will drop it
  * before returning. Used to avoid races in establishing new handles when
  * importing an object from either an flink name or a dma-buf.
+ *
+ * Handles must be release again through drm_gem_handle_delete(). This is done
+ * when userspace closes @file_priv for all attached handles, or through the
+ * GEM_CLOSE ioctl for individual handles.
  */
 int
 drm_gem_handle_create_tail(struct drm_file *file_priv,
@@ -541,7 +546,17 @@
 }
 EXPORT_SYMBOL(drm_gem_put_pages);
 
-/** Returns a reference to the object named by the handle. */
+/**
+ * drm_gem_object_lookup - look up a GEM object from it's handle
+ * @dev: DRM device
+ * @filp: DRM file private date
+ * @handle: userspace handle
+ *
+ * Returns:
+ *
+ * A reference to the object named by the handle if such exists on @filp, NULL
+ * otherwise.
+ */
 struct drm_gem_object *
 drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
 		      u32 handle)
@@ -774,6 +789,13 @@
 }
 EXPORT_SYMBOL(drm_gem_object_free);
 
+/**
+ * drm_gem_vm_open - vma->ops->open implementation for GEM
+ * @vma: VM area structure
+ *
+ * This function implements the #vm_operations_struct open() callback for GEM
+ * drivers. This must be used together with drm_gem_vm_close().
+ */
 void drm_gem_vm_open(struct vm_area_struct *vma)
 {
 	struct drm_gem_object *obj = vma->vm_private_data;
@@ -782,6 +804,13 @@
 }
 EXPORT_SYMBOL(drm_gem_vm_open);
 
+/**
+ * drm_gem_vm_close - vma->ops->close implementation for GEM
+ * @vma: VM area structure
+ *
+ * This function implements the #vm_operations_struct close() callback for GEM
+ * drivers. This must be used together with drm_gem_vm_open().
+ */
 void drm_gem_vm_close(struct vm_area_struct *vma)
 {
 	struct drm_gem_object *obj = vma->vm_private_data;
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index cd74a09..ef6bd36 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -917,13 +917,30 @@
 	} else if (mode1->clock != mode2->clock)
 		return false;
 
+	return drm_mode_equal_no_clocks(mode1, mode2);
+}
+EXPORT_SYMBOL(drm_mode_equal);
+
+/**
+ * drm_mode_equal_no_clocks - test modes for equality
+ * @mode1: first mode
+ * @mode2: second mode
+ *
+ * Check to see if @mode1 and @mode2 are equivalent, but
+ * don't check the pixel clocks.
+ *
+ * Returns:
+ * True if the modes are equal, false otherwise.
+ */
+bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
+{
 	if ((mode1->flags & DRM_MODE_FLAG_3D_MASK) !=
 	    (mode2->flags & DRM_MODE_FLAG_3D_MASK))
 		return false;
 
 	return drm_mode_equal_no_clocks_no_stereo(mode1, mode2);
 }
-EXPORT_SYMBOL(drm_mode_equal);
+EXPORT_SYMBOL(drm_mode_equal_no_clocks);
 
 /**
  * drm_mode_equal_no_clocks_no_stereo - test modes for equality
@@ -1230,7 +1247,7 @@
 	unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
 	bool yres_specified = false, cvt = false, rb = false;
 	bool interlace = false, margins = false, was_digit = false;
-	int i;
+	int i, err;
 	enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
 
 #ifdef CONFIG_FB
@@ -1250,7 +1267,9 @@
 		case '@':
 			if (!refresh_specified && !bpp_specified &&
 			    !yres_specified && !cvt && !rb && was_digit) {
-				refresh = simple_strtol(&name[i+1], NULL, 10);
+				err = kstrtouint(&name[i + 1], 10, &refresh);
+				if (err)
+					return false;
 				refresh_specified = true;
 				was_digit = false;
 			} else
@@ -1259,7 +1278,9 @@
 		case '-':
 			if (!bpp_specified && !yres_specified && !cvt &&
 			    !rb && was_digit) {
-				bpp = simple_strtol(&name[i+1], NULL, 10);
+				err = kstrtouint(&name[i + 1], 10, &bpp);
+				if (err)
+					return false;
 				bpp_specified = true;
 				was_digit = false;
 			} else
@@ -1267,7 +1288,9 @@
 			break;
 		case 'x':
 			if (!yres_specified && was_digit) {
-				yres = simple_strtol(&name[i+1], NULL, 10);
+				err = kstrtouint(&name[i + 1], 10, &yres);
+				if (err)
+					return false;
 				yres_specified = true;
 				was_digit = false;
 			} else
@@ -1491,4 +1514,4 @@
 
 out:
 	return ret;
-}
\ No newline at end of file
+}
diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c
index 6675b14..c2f5971 100644
--- a/drivers/gpu/drm/drm_modeset_lock.c
+++ b/drivers/gpu/drm/drm_modeset_lock.c
@@ -57,11 +57,18 @@
 
 /**
  * drm_modeset_lock_all - take all modeset locks
- * @dev: drm device
+ * @dev: DRM device
  *
  * This function takes all modeset locks, suitable where a more fine-grained
- * scheme isn't (yet) implemented. Locks must be dropped with
- * drm_modeset_unlock_all.
+ * scheme isn't (yet) implemented. Locks must be dropped by calling the
+ * drm_modeset_unlock_all() function.
+ *
+ * This function is deprecated. It allocates a lock acquisition context and
+ * stores it in the DRM device's ->mode_config. This facilitate conversion of
+ * existing code because it removes the need to manually deal with the
+ * acquisition context, but it is also brittle because the context is global
+ * and care must be taken not to nest calls. New code should use the
+ * drm_modeset_lock_all_ctx() function and pass in the context explicitly.
  */
 void drm_modeset_lock_all(struct drm_device *dev)
 {
@@ -78,39 +85,43 @@
 	drm_modeset_acquire_init(ctx, 0);
 
 retry:
-	ret = drm_modeset_lock(&config->connection_mutex, ctx);
-	if (ret)
-		goto fail;
-	ret = drm_modeset_lock_all_crtcs(dev, ctx);
-	if (ret)
-		goto fail;
+	ret = drm_modeset_lock_all_ctx(dev, ctx);
+	if (ret < 0) {
+		if (ret == -EDEADLK) {
+			drm_modeset_backoff(ctx);
+			goto retry;
+		}
+
+		drm_modeset_acquire_fini(ctx);
+		kfree(ctx);
+		return;
+	}
 
 	WARN_ON(config->acquire_ctx);
 
-	/* now we hold the locks, so now that it is safe, stash the
-	 * ctx for drm_modeset_unlock_all():
+	/*
+	 * We hold the locks now, so it is safe to stash the acquisition
+	 * context for drm_modeset_unlock_all().
 	 */
 	config->acquire_ctx = ctx;
 
 	drm_warn_on_modeset_not_all_locked(dev);
-
-	return;
-
-fail:
-	if (ret == -EDEADLK) {
-		drm_modeset_backoff(ctx);
-		goto retry;
-	}
-
-	kfree(ctx);
 }
 EXPORT_SYMBOL(drm_modeset_lock_all);
 
 /**
  * drm_modeset_unlock_all - drop all modeset locks
- * @dev: device
+ * @dev: DRM device
  *
- * This function drop all modeset locks taken by drm_modeset_lock_all.
+ * This function drops all modeset locks taken by a previous call to the
+ * drm_modeset_lock_all() function.
+ *
+ * This function is deprecated. It uses the lock acquisition context stored
+ * in the DRM device's ->mode_config. This facilitates conversion of existing
+ * code because it removes the need to manually deal with the acquisition
+ * context, but it is also brittle because the context is global and care must
+ * be taken not to nest calls. New code should pass the acquisition context
+ * directly to the drm_modeset_drop_locks() function.
  */
 void drm_modeset_unlock_all(struct drm_device *dev)
 {
@@ -431,14 +442,34 @@
 }
 EXPORT_SYMBOL(drm_modeset_unlock);
 
-/* In some legacy codepaths it's convenient to just grab all the crtc and plane
- * related locks. */
-int drm_modeset_lock_all_crtcs(struct drm_device *dev,
-		struct drm_modeset_acquire_ctx *ctx)
+/**
+ * drm_modeset_lock_all_ctx - take all modeset locks
+ * @dev: DRM device
+ * @ctx: lock acquisition context
+ *
+ * This function takes all modeset locks, suitable where a more fine-grained
+ * scheme isn't (yet) implemented.
+ *
+ * Unlike drm_modeset_lock_all(), it doesn't take the dev->mode_config.mutex
+ * since that lock isn't required for modeset state changes. Callers which
+ * need to grab that lock too need to do so outside of the acquire context
+ * @ctx.
+ *
+ * Locks acquired with this function should be released by calling the
+ * drm_modeset_drop_locks() function on @ctx.
+ *
+ * Returns: 0 on success or a negative error-code on failure.
+ */
+int drm_modeset_lock_all_ctx(struct drm_device *dev,
+			     struct drm_modeset_acquire_ctx *ctx)
 {
 	struct drm_crtc *crtc;
 	struct drm_plane *plane;
-	int ret = 0;
+	int ret;
+
+	ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
+	if (ret)
+		return ret;
 
 	drm_for_each_crtc(crtc, dev) {
 		ret = drm_modeset_lock(&crtc->mutex, ctx);
@@ -454,4 +485,4 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(drm_modeset_lock_all_crtcs);
+EXPORT_SYMBOL(drm_modeset_lock_all_ctx);
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index d384ebc..a6983d4 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -164,6 +164,8 @@
 	vscale = drm_rect_calc_vscale(src, dest, min_scale, max_scale);
 	if (hscale < 0 || vscale < 0) {
 		DRM_DEBUG_KMS("Invalid scaling of plane\n");
+		drm_rect_debug_print("src: ", src, true);
+		drm_rect_debug_print("dst: ", dest, false);
 		return -ERANGE;
 	}
 
@@ -180,6 +182,8 @@
 
 	if (!can_position && !drm_rect_equals(dest, clip)) {
 		DRM_DEBUG_KMS("Plane must cover entire CRTC\n");
+		drm_rect_debug_print("dst: ", dest, false);
+		drm_rect_debug_print("clip: ", clip, false);
 		return -EINVAL;
 	}
 
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index f8b5fcf..bfdf5bb 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -147,6 +147,8 @@
 	list_for_each_entry(mode, &connector->modes, head)
 		mode->status = MODE_UNVERIFIED;
 
+	old_status = connector->status;
+
 	if (connector->force) {
 		if (connector->force == DRM_FORCE_ON ||
 		    connector->force == DRM_FORCE_ON_DIGITAL)
@@ -156,33 +158,32 @@
 		if (connector->funcs->force)
 			connector->funcs->force(connector);
 	} else {
-		old_status = connector->status;
-
 		connector->status = connector->funcs->detect(connector, true);
+	}
+
+	/*
+	 * Normally either the driver's hpd code or the poll loop should
+	 * pick up any changes and fire the hotplug event. But if
+	 * userspace sneaks in a probe, we might miss a change. Hence
+	 * check here, and if anything changed start the hotplug code.
+	 */
+	if (old_status != connector->status) {
+		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
+			      connector->base.id,
+			      connector->name,
+			      drm_get_connector_status_name(old_status),
+			      drm_get_connector_status_name(connector->status));
 
 		/*
-		 * Normally either the driver's hpd code or the poll loop should
-		 * pick up any changes and fire the hotplug event. But if
-		 * userspace sneaks in a probe, we might miss a change. Hence
-		 * check here, and if anything changed start the hotplug code.
+		 * The hotplug event code might call into the fb
+		 * helpers, and so expects that we do not hold any
+		 * locks. Fire up the poll struct instead, it will
+		 * disable itself again.
 		 */
-		if (old_status != connector->status) {
-			DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
-				      connector->base.id,
-				      connector->name,
-				      old_status, connector->status);
-
-			/*
-			 * The hotplug event code might call into the fb
-			 * helpers, and so expects that we do not hold any
-			 * locks. Fire up the poll struct instead, it will
-			 * disable itself again.
-			 */
-			dev->mode_config.delayed_event = true;
-			if (dev->mode_config.poll_enabled)
-				schedule_delayed_work(&dev->mode_config.output_poll_work,
-						      0);
-		}
+		dev->mode_config.delayed_event = true;
+		if (dev->mode_config.poll_enabled)
+			schedule_delayed_work(&dev->mode_config.output_poll_work,
+					      0);
 	}
 
 	/* Re-enable polling in case the global poll config changed. */
diff --git a/drivers/gpu/drm/drm_rect.c b/drivers/gpu/drm/drm_rect.c
index 531ac4c..a8e2c86 100644
--- a/drivers/gpu/drm/drm_rect.c
+++ b/drivers/gpu/drm/drm_rect.c
@@ -275,22 +275,23 @@
 
 /**
  * drm_rect_debug_print - print the rectangle information
+ * @prefix: prefix string
  * @r: rectangle to print
  * @fixed_point: rectangle is in 16.16 fixed point format
  */
-void drm_rect_debug_print(const struct drm_rect *r, bool fixed_point)
+void drm_rect_debug_print(const char *prefix, const struct drm_rect *r, bool fixed_point)
 {
 	int w = drm_rect_width(r);
 	int h = drm_rect_height(r);
 
 	if (fixed_point)
-		DRM_DEBUG_KMS("%d.%06ux%d.%06u%+d.%06u%+d.%06u\n",
+		DRM_DEBUG_KMS("%s%d.%06ux%d.%06u%+d.%06u%+d.%06u\n", prefix,
 			      w >> 16, ((w & 0xffff) * 15625) >> 10,
 			      h >> 16, ((h & 0xffff) * 15625) >> 10,
 			      r->x1 >> 16, ((r->x1 & 0xffff) * 15625) >> 10,
 			      r->y1 >> 16, ((r->y1 & 0xffff) * 15625) >> 10);
 	else
-		DRM_DEBUG_KMS("%dx%d%+d%+d\n", w, h, r->x1, r->y1);
+		DRM_DEBUG_KMS("%s%dx%d%+d%+d\n", prefix, w, h, r->x1, r->y1);
 }
 EXPORT_SYMBOL(drm_rect_debug_print);
 
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 615b7e6..0ca6410 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -167,47 +167,35 @@
 {
 	struct drm_connector *connector = to_drm_connector(device);
 	struct drm_device *dev = connector->dev;
-	enum drm_connector_status old_status;
+	enum drm_connector_force old_force;
 	int ret;
 
 	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
 	if (ret)
 		return ret;
 
-	old_status = connector->status;
+	old_force = connector->force;
 
-	if (sysfs_streq(buf, "detect")) {
+	if (sysfs_streq(buf, "detect"))
 		connector->force = 0;
-		connector->status = connector->funcs->detect(connector, true);
-	} else if (sysfs_streq(buf, "on")) {
+	else if (sysfs_streq(buf, "on"))
 		connector->force = DRM_FORCE_ON;
-	} else if (sysfs_streq(buf, "on-digital")) {
+	else if (sysfs_streq(buf, "on-digital"))
 		connector->force = DRM_FORCE_ON_DIGITAL;
-	} else if (sysfs_streq(buf, "off")) {
+	else if (sysfs_streq(buf, "off"))
 		connector->force = DRM_FORCE_OFF;
-	} else
+	else
 		ret = -EINVAL;
 
-	if (ret == 0 && connector->force) {
-		if (connector->force == DRM_FORCE_ON ||
-		    connector->force == DRM_FORCE_ON_DIGITAL)
-			connector->status = connector_status_connected;
-		else
-			connector->status = connector_status_disconnected;
-		if (connector->funcs->force)
-			connector->funcs->force(connector);
-	}
-
-	if (old_status != connector->status) {
-		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
+	if (old_force != connector->force || !connector->force) {
+		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force updated from %d to %d or reprobing\n",
 			      connector->base.id,
 			      connector->name,
-			      old_status, connector->status);
+			      old_force, connector->force);
 
-		dev->mode_config.delayed_event = true;
-		if (dev->mode_config.poll_enabled)
-			schedule_delayed_work(&dev->mode_config.output_poll_work,
-					      0);
+		connector->funcs->fill_modes(connector,
+					     dev->mode_config.max_width,
+					     dev->mode_config.max_height);
 	}
 
 	mutex_unlock(&dev->mode_config.mutex);
@@ -256,23 +244,29 @@
 	struct drm_connector *connector = to_drm_connector(connector_dev);
 	unsigned char *edid;
 	size_t size;
+	ssize_t ret = 0;
 
+	mutex_lock(&connector->dev->mode_config.mutex);
 	if (!connector->edid_blob_ptr)
-		return 0;
+		goto unlock;
 
 	edid = connector->edid_blob_ptr->data;
 	size = connector->edid_blob_ptr->length;
 	if (!edid)
-		return 0;
+		goto unlock;
 
 	if (off >= size)
-		return 0;
+		goto unlock;
 
 	if (off + count > size)
 		count = size - off;
 	memcpy(buf, edid + off, count);
 
-	return count;
+	ret = count;
+unlock:
+	mutex_unlock(&connector->dev->mode_config.mutex);
+
+	return ret;
 }
 
 static ssize_t modes_show(struct device *device,
@@ -283,10 +277,12 @@
 	struct drm_display_mode *mode;
 	int written = 0;
 
+	mutex_lock(&connector->dev->mode_config.mutex);
 	list_for_each_entry(mode, &connector->modes, head) {
 		written += snprintf(buf + written, PAGE_SIZE - written, "%s\n",
 				    mode->name);
 	}
+	mutex_unlock(&connector->dev->mode_config.mutex);
 
 	return written;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index fcea28b..49b9bc3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -117,7 +117,7 @@
 
 struct drm_framebuffer *
 exynos_drm_framebuffer_init(struct drm_device *dev,
-			    struct drm_mode_fb_cmd2 *mode_cmd,
+			    const struct drm_mode_fb_cmd2 *mode_cmd,
 			    struct exynos_drm_gem **exynos_gem,
 			    int count)
 {
@@ -154,7 +154,7 @@
 
 static struct drm_framebuffer *
 exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
-		      struct drm_mode_fb_cmd2 *mode_cmd)
+		      const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
 	struct drm_gem_object *obj;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h
index cf39f98..6fa0e47 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h
@@ -18,7 +18,7 @@
 
 struct drm_framebuffer *
 exynos_drm_framebuffer_init(struct drm_device *dev,
-			    struct drm_mode_fb_cmd2 *mode_cmd,
+			    const struct drm_mode_fb_cmd2 *mode_cmd,
 			    struct exynos_drm_gem **exynos_gem,
 			    int count);
 
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index 72bc979..cb95765 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -243,7 +243,7 @@
  */
 static int psb_framebuffer_init(struct drm_device *dev,
 					struct psb_framebuffer *fb,
-					struct drm_mode_fb_cmd2 *mode_cmd,
+					const struct drm_mode_fb_cmd2 *mode_cmd,
 					struct gtt_range *gt)
 {
 	u32 bpp, depth;
@@ -286,7 +286,7 @@
 
 static struct drm_framebuffer *psb_framebuffer_create
 			(struct drm_device *dev,
-			 struct drm_mode_fb_cmd2 *mode_cmd,
+			 const struct drm_mode_fb_cmd2 *mode_cmd,
 			 struct gtt_range *gt)
 {
 	struct psb_framebuffer *fb;
@@ -408,8 +408,6 @@
 
 	memset(dev_priv->vram_addr + backing->offset, 0, size);
 
-	mutex_lock(&dev->struct_mutex);
-
 	info = drm_fb_helper_alloc_fbi(&fbdev->psb_fb_helper);
 	if (IS_ERR(info)) {
 		ret = PTR_ERR(info);
@@ -465,17 +463,15 @@
 	dev_dbg(dev->dev, "allocated %dx%d fb\n",
 					psbfb->base.width, psbfb->base.height);
 
-	mutex_unlock(&dev->struct_mutex);
 	return 0;
 out_unref:
 	if (backing->stolen)
 		psb_gtt_free_range(dev, backing);
 	else
-		drm_gem_object_unreference(&backing->gem);
+		drm_gem_object_unreference_unlocked(&backing->gem);
 
 	drm_fb_helper_release_fbi(&fbdev->psb_fb_helper);
 out_err1:
-	mutex_unlock(&dev->struct_mutex);
 	psb_gtt_free_range(dev, backing);
 	return ret;
 }
@@ -490,7 +486,7 @@
  */
 static struct drm_framebuffer *psb_user_framebuffer_create
 			(struct drm_device *dev, struct drm_file *filp,
-			 struct drm_mode_fb_cmd2 *cmd)
+			 const struct drm_mode_fb_cmd2 *cmd)
 {
 	struct gtt_range *r;
 	struct drm_gem_object *obj;
@@ -571,7 +567,7 @@
 	drm_framebuffer_cleanup(&psbfb->base);
 
 	if (psbfb->gtt)
-		drm_gem_object_unreference(&psbfb->gtt->gem);
+		drm_gem_object_unreference_unlocked(&psbfb->gtt->gem);
 	return 0;
 }
 
@@ -786,12 +782,8 @@
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	if (dev_priv->modeset) {
-		mutex_lock(&dev->struct_mutex);
-
 		drm_kms_helper_poll_fini(dev);
 		psb_fbdev_fini(dev);
 		drm_mode_config_cleanup(dev);
-
-		mutex_unlock(&dev->struct_mutex);
 	}
 }
diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c
index c707fa6..506224b 100644
--- a/drivers/gpu/drm/gma500/gem.c
+++ b/drivers/gpu/drm/gma500/gem.c
@@ -62,15 +62,10 @@
 	int ret = 0;
 	struct drm_gem_object *obj;
 
-	mutex_lock(&dev->struct_mutex);
-
 	/* GEM does all our handle to object mapping */
 	obj = drm_gem_object_lookup(dev, file, handle);
-	if (obj == NULL) {
-		ret = -ENOENT;
-		goto unlock;
-	}
-	/* What validation is needed here ? */
+	if (obj == NULL)
+		return -ENOENT;
 
 	/* Make it mmapable */
 	ret = drm_gem_create_mmap_offset(obj);
@@ -78,9 +73,7 @@
 		goto out;
 	*offset = drm_vma_node_offset_addr(&obj->vma_node);
 out:
-	drm_gem_object_unreference(obj);
-unlock:
-	mutex_unlock(&dev->struct_mutex);
+	drm_gem_object_unreference_unlocked(obj);
 	return ret;
 }
 
@@ -130,7 +123,7 @@
 		return ret;
 	}
 	/* We have the initial and handle reference but need only one now */
-	drm_gem_object_unreference(&r->gem);
+	drm_gem_object_unreference_unlocked(&r->gem);
 	*handlep = handle;
 	return 0;
 }
@@ -189,7 +182,7 @@
 
 	/* Make sure we don't parallel update on a fault, nor move or remove
 	   something from beneath our feet */
-	mutex_lock(&dev->struct_mutex);
+	mutex_lock(&dev_priv->mmap_mutex);
 
 	/* For now the mmap pins the object and it stays pinned. As things
 	   stand that will do us no harm */
@@ -215,7 +208,7 @@
 	ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
 
 fail:
-	mutex_unlock(&dev->struct_mutex);
+	mutex_unlock(&dev_priv->mmap_mutex);
 	switch (ret) {
 	case 0:
 	case -ERESTARTSYS:
diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c
index 001b450..ff17af4 100644
--- a/drivers/gpu/drm/gma500/gma_display.c
+++ b/drivers/gpu/drm/gma500/gma_display.c
@@ -349,8 +349,6 @@
 	/* If we didn't get a handle then turn the cursor off */
 	if (!handle) {
 		temp = CURSOR_MODE_DISABLE;
-		mutex_lock(&dev->struct_mutex);
-
 		if (gma_power_begin(dev, false)) {
 			REG_WRITE(control, temp);
 			REG_WRITE(base, 0);
@@ -362,11 +360,9 @@
 			gt = container_of(gma_crtc->cursor_obj,
 					  struct gtt_range, gem);
 			psb_gtt_unpin(gt);
-			drm_gem_object_unreference(gma_crtc->cursor_obj);
+			drm_gem_object_unreference_unlocked(gma_crtc->cursor_obj);
 			gma_crtc->cursor_obj = NULL;
 		}
-
-		mutex_unlock(&dev->struct_mutex);
 		return 0;
 	}
 
@@ -376,7 +372,6 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&dev->struct_mutex);
 	obj = drm_gem_object_lookup(dev, file_priv, handle);
 	if (!obj) {
 		ret = -ENOENT;
@@ -441,17 +436,15 @@
 	if (gma_crtc->cursor_obj) {
 		gt = container_of(gma_crtc->cursor_obj, struct gtt_range, gem);
 		psb_gtt_unpin(gt);
-		drm_gem_object_unreference(gma_crtc->cursor_obj);
+		drm_gem_object_unreference_unlocked(gma_crtc->cursor_obj);
 	}
 
 	gma_crtc->cursor_obj = obj;
 unlock:
-	mutex_unlock(&dev->struct_mutex);
 	return ret;
 
 unref_cursor:
-	drm_gem_object_unreference(obj);
-	mutex_unlock(&dev->struct_mutex);
+	drm_gem_object_unreference_unlocked(obj);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c
index ce015db..8f69225 100644
--- a/drivers/gpu/drm/gma500/gtt.c
+++ b/drivers/gpu/drm/gma500/gtt.c
@@ -425,6 +425,7 @@
 
 	if (!resume) {
 		mutex_init(&dev_priv->gtt_mutex);
+		mutex_init(&dev_priv->mmap_mutex);
 		psb_gtt_alloc(dev);
 	}
 
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h
index e21726e..3bd2c72 100644
--- a/drivers/gpu/drm/gma500/psb_drv.h
+++ b/drivers/gpu/drm/gma500/psb_drv.h
@@ -465,6 +465,8 @@
 	struct mutex gtt_mutex;
 	struct resource *gtt_mem;	/* Our PCI resource */
 
+	struct mutex mmap_mutex;
+
 	struct psb_mmu_driver *mmu;
 	struct psb_mmu_pd *pf_pd;
 
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index 051eab3..fcd77b2 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -10,6 +10,7 @@
 	# the shmem_readpage() which depends upon tmpfs
 	select SHMEM
 	select TMPFS
+	select STOP_MACHINE
 	select DRM_KMS_HELPER
 	select DRM_PANEL
 	select DRM_MIPI_DSI
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 44d290a..0851de07 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -77,6 +77,7 @@
 	  dvo_tfp410.o \
 	  intel_crt.o \
 	  intel_ddi.o \
+	  intel_dp_link_training.o \
 	  intel_dp_mst.o \
 	  intel_dp.o \
 	  intel_dsi.o \
diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h
index 0e2c1b9..13dea42 100644
--- a/drivers/gpu/drm/i915/dvo.h
+++ b/drivers/gpu/drm/i915/dvo.h
@@ -32,7 +32,8 @@
 	const char *name;
 	int type;
 	/* DVOA/B/C output register */
-	u32 dvo_reg;
+	i915_reg_t dvo_reg;
+	i915_reg_t dvo_srcdim_reg;
 	/* GPIO register used for i2c bus to control this device */
 	u32 gpio;
 	int slave_addr;
diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c
index db58c8d..814d894 100644
--- a/drivers/gpu/drm/i915/i915_cmd_parser.c
+++ b/drivers/gpu/drm/i915/i915_cmd_parser.c
@@ -407,14 +407,14 @@
  * LRI.
  */
 struct drm_i915_reg_descriptor {
-	u32 addr;
+	i915_reg_t addr;
 	u32 mask;
 	u32 value;
 };
 
 /* Convenience macro for adding 32-bit registers. */
-#define REG32(address, ...)                             \
-	{ .addr = address, __VA_ARGS__ }
+#define REG32(_reg, ...) \
+	{ .addr = (_reg), __VA_ARGS__ }
 
 /*
  * Convenience macro for adding 64-bit registers.
@@ -423,8 +423,13 @@
  * access commands only allow 32-bit accesses. Hence, we have to include
  * entries for both halves of the 64-bit registers.
  */
-#define REG64(addr)                                     \
-	REG32(addr), REG32(addr + sizeof(u32))
+#define REG64(_reg) \
+	{ .addr = _reg }, \
+	{ .addr = _reg ## _UDW }
+
+#define REG64_IDX(_reg, idx) \
+	{ .addr = _reg(idx) }, \
+	{ .addr = _reg ## _UDW(idx) }
 
 static const struct drm_i915_reg_descriptor gen7_render_regs[] = {
 	REG64(GPGPU_THREADS_DISPATCHED),
@@ -451,14 +456,14 @@
 	REG32(GEN7_GPGPU_DISPATCHDIMX),
 	REG32(GEN7_GPGPU_DISPATCHDIMY),
 	REG32(GEN7_GPGPU_DISPATCHDIMZ),
-	REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)),
-	REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)),
-	REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)),
-	REG64(GEN7_SO_NUM_PRIMS_WRITTEN(3)),
-	REG64(GEN7_SO_PRIM_STORAGE_NEEDED(0)),
-	REG64(GEN7_SO_PRIM_STORAGE_NEEDED(1)),
-	REG64(GEN7_SO_PRIM_STORAGE_NEEDED(2)),
-	REG64(GEN7_SO_PRIM_STORAGE_NEEDED(3)),
+	REG64_IDX(GEN7_SO_NUM_PRIMS_WRITTEN, 0),
+	REG64_IDX(GEN7_SO_NUM_PRIMS_WRITTEN, 1),
+	REG64_IDX(GEN7_SO_NUM_PRIMS_WRITTEN, 2),
+	REG64_IDX(GEN7_SO_NUM_PRIMS_WRITTEN, 3),
+	REG64_IDX(GEN7_SO_PRIM_STORAGE_NEEDED, 0),
+	REG64_IDX(GEN7_SO_PRIM_STORAGE_NEEDED, 1),
+	REG64_IDX(GEN7_SO_PRIM_STORAGE_NEEDED, 2),
+	REG64_IDX(GEN7_SO_PRIM_STORAGE_NEEDED, 3),
 	REG32(GEN7_SO_WRITE_OFFSET(0)),
 	REG32(GEN7_SO_WRITE_OFFSET(1)),
 	REG32(GEN7_SO_WRITE_OFFSET(2)),
@@ -592,7 +597,7 @@
 	bool ret = true;
 
 	for (i = 0; i < reg_count; i++) {
-		u32 curr = reg_table[i].addr;
+		u32 curr = i915_mmio_reg_offset(reg_table[i].addr);
 
 		if (curr < previous) {
 			DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n",
@@ -847,7 +852,7 @@
 		int i;
 
 		for (i = 0; i < count; i++) {
-			if (table[i].addr == addr)
+			if (i915_mmio_reg_offset(table[i].addr) == addr)
 				return &table[i];
 		}
 	}
@@ -1023,7 +1028,7 @@
 			 * to the register. Hence, limit OACONTROL writes to
 			 * only MI_LOAD_REGISTER_IMM commands.
 			 */
-			if (reg_addr == OACONTROL) {
+			if (reg_addr == i915_mmio_reg_offset(OACONTROL)) {
 				if (desc->cmd.value == MI_LOAD_REGISTER_MEM) {
 					DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n");
 					return false;
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 8aab974..411a9c6 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1252,18 +1252,21 @@
 
 		max_freq = (IS_BROXTON(dev) ? rp_state_cap >> 0 :
 			    rp_state_cap >> 16) & 0xff;
-		max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1);
+		max_freq *= (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
+			     GEN9_FREQ_SCALER : 1);
 		seq_printf(m, "Lowest (RPN) frequency: %dMHz\n",
 			   intel_gpu_freq(dev_priv, max_freq));
 
 		max_freq = (rp_state_cap & 0xff00) >> 8;
-		max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1);
+		max_freq *= (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
+			     GEN9_FREQ_SCALER : 1);
 		seq_printf(m, "Nominal (RP1) frequency: %dMHz\n",
 			   intel_gpu_freq(dev_priv, max_freq));
 
 		max_freq = (IS_BROXTON(dev) ? rp_state_cap >> 16 :
 			    rp_state_cap >> 0) & 0xff;
-		max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1);
+		max_freq *= (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
+			     GEN9_FREQ_SCALER : 1);
 		seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
 			   intel_gpu_freq(dev_priv, max_freq));
 		seq_printf(m, "Max overclocked frequency: %dMHz\n",
@@ -1523,7 +1526,7 @@
 		seq_printf(m, "RC information accurate: %s\n", yesno(count < 51));
 	}
 
-	gt_core_status = readl(dev_priv->regs + GEN6_GT_CORE_STATUS);
+	gt_core_status = I915_READ_FW(GEN6_GT_CORE_STATUS);
 	trace_i915_reg_rw(false, GEN6_GT_CORE_STATUS, gt_core_status, 4, true);
 
 	rpmodectl1 = I915_READ(GEN6_RP_CONTROL);
@@ -1640,7 +1643,7 @@
 		seq_puts(m, "FBC enabled\n");
 	else
 		seq_printf(m, "FBC disabled: %s\n",
-			  intel_no_fbc_reason_str(dev_priv->fbc.no_fbc_reason));
+			   dev_priv->fbc.no_fbc_reason);
 
 	if (INTEL_INFO(dev_priv)->gen >= 7)
 		seq_printf(m, "Compressing: %s\n",
@@ -1801,7 +1804,7 @@
 	if (ret)
 		goto out;
 
-	if (IS_SKYLAKE(dev)) {
+	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
 		/* Convert GT frequency to 50 HZ units */
 		min_gpu_freq =
 			dev_priv->rps.min_freq_softlimit / GEN9_FREQ_SCALER;
@@ -1821,7 +1824,8 @@
 				       &ia_freq);
 		seq_printf(m, "%d\t\t%d\t\t\t\t%d\n",
 			   intel_gpu_freq(dev_priv, (gpu_freq *
-				(IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1))),
+				(IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
+				 GEN9_FREQ_SCALER : 1))),
 			   ((ia_freq >> 0) & 0xff) * 100,
 			   ((ia_freq >> 8) & 0xff) * 100);
 	}
@@ -1873,17 +1877,19 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	ifbdev = dev_priv->fbdev;
-	fb = to_intel_framebuffer(ifbdev->helper.fb);
+	if (ifbdev) {
+		fb = to_intel_framebuffer(ifbdev->helper.fb);
 
-	seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ",
-		   fb->base.width,
-		   fb->base.height,
-		   fb->base.depth,
-		   fb->base.bits_per_pixel,
-		   fb->base.modifier[0],
-		   atomic_read(&fb->base.refcount.refcount));
-	describe_obj(m, fb->obj);
-	seq_putc(m, '\n');
+		seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ",
+			   fb->base.width,
+			   fb->base.height,
+			   fb->base.depth,
+			   fb->base.bits_per_pixel,
+			   fb->base.modifier[0],
+			   atomic_read(&fb->base.refcount.refcount));
+		describe_obj(m, fb->obj);
+		seq_putc(m, '\n');
+	}
 #endif
 
 	mutex_lock(&dev->mode_config.fb_lock);
@@ -2402,6 +2408,12 @@
 		guc_fw->guc_fw_major_wanted, guc_fw->guc_fw_minor_wanted);
 	seq_printf(m, "\tversion found: %d.%d\n",
 		guc_fw->guc_fw_major_found, guc_fw->guc_fw_minor_found);
+	seq_printf(m, "\theader: offset is %d; size = %d\n",
+		guc_fw->header_offset, guc_fw->header_size);
+	seq_printf(m, "\tuCode: offset is %d; size = %d\n",
+		guc_fw->ucode_offset, guc_fw->ucode_size);
+	seq_printf(m, "\tRSA: offset is %d; size = %d\n",
+		guc_fw->rsa_offset, guc_fw->rsa_size);
 
 	tmp = I915_READ(GUC_STATUS);
 
@@ -2550,7 +2562,7 @@
 		   yesno(work_busy(&dev_priv->psr.work.work)));
 
 	if (HAS_DDI(dev))
-		enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+		enabled = I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE;
 	else {
 		for_each_pipe(dev_priv, pipe) {
 			stat[pipe] = I915_READ(VLV_PSRSTAT(pipe)) &
@@ -2572,7 +2584,7 @@
 
 	/* CHV PSR has no kind of performance counter */
 	if (HAS_DDI(dev)) {
-		psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
+		psrperf = I915_READ(EDP_PSR_PERF_CNT) &
 			EDP_PSR_PERF_CNT_MASK;
 
 		seq_printf(m, "Performance_Counter: %u\n", psrperf);
@@ -2696,24 +2708,16 @@
 		return "TRANSCODER_C";
 	case POWER_DOMAIN_TRANSCODER_EDP:
 		return "TRANSCODER_EDP";
-	case POWER_DOMAIN_PORT_DDI_A_2_LANES:
-		return "PORT_DDI_A_2_LANES";
-	case POWER_DOMAIN_PORT_DDI_A_4_LANES:
-		return "PORT_DDI_A_4_LANES";
-	case POWER_DOMAIN_PORT_DDI_B_2_LANES:
-		return "PORT_DDI_B_2_LANES";
-	case POWER_DOMAIN_PORT_DDI_B_4_LANES:
-		return "PORT_DDI_B_4_LANES";
-	case POWER_DOMAIN_PORT_DDI_C_2_LANES:
-		return "PORT_DDI_C_2_LANES";
-	case POWER_DOMAIN_PORT_DDI_C_4_LANES:
-		return "PORT_DDI_C_4_LANES";
-	case POWER_DOMAIN_PORT_DDI_D_2_LANES:
-		return "PORT_DDI_D_2_LANES";
-	case POWER_DOMAIN_PORT_DDI_D_4_LANES:
-		return "PORT_DDI_D_4_LANES";
-	case POWER_DOMAIN_PORT_DDI_E_2_LANES:
-		return "PORT_DDI_E_2_LANES";
+	case POWER_DOMAIN_PORT_DDI_A_LANES:
+		return "PORT_DDI_A_LANES";
+	case POWER_DOMAIN_PORT_DDI_B_LANES:
+		return "PORT_DDI_B_LANES";
+	case POWER_DOMAIN_PORT_DDI_C_LANES:
+		return "PORT_DDI_C_LANES";
+	case POWER_DOMAIN_PORT_DDI_D_LANES:
+		return "PORT_DDI_D_LANES";
+	case POWER_DOMAIN_PORT_DDI_E_LANES:
+		return "PORT_DDI_E_LANES";
 	case POWER_DOMAIN_PORT_DSI:
 		return "PORT_DSI";
 	case POWER_DOMAIN_PORT_CRT:
@@ -2736,6 +2740,8 @@
 		return "AUX_D";
 	case POWER_DOMAIN_GMBUS:
 		return "GMBUS";
+	case POWER_DOMAIN_MODESET:
+		return "MODESET";
 	case POWER_DOMAIN_INIT:
 		return "INIT";
 	default:
@@ -2779,6 +2785,51 @@
 	return 0;
 }
 
+static int i915_dmc_info(struct seq_file *m, void *unused)
+{
+	struct drm_info_node *node = m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_csr *csr;
+
+	if (!HAS_CSR(dev)) {
+		seq_puts(m, "not supported\n");
+		return 0;
+	}
+
+	csr = &dev_priv->csr;
+
+	intel_runtime_pm_get(dev_priv);
+
+	seq_printf(m, "fw loaded: %s\n", yesno(csr->dmc_payload != NULL));
+	seq_printf(m, "path: %s\n", csr->fw_path);
+
+	if (!csr->dmc_payload)
+		goto out;
+
+	seq_printf(m, "version: %d.%d\n", CSR_VERSION_MAJOR(csr->version),
+		   CSR_VERSION_MINOR(csr->version));
+
+	if (IS_SKYLAKE(dev) && csr->version >= CSR_VERSION(1, 6)) {
+		seq_printf(m, "DC3 -> DC5 count: %d\n",
+			   I915_READ(SKL_CSR_DC3_DC5_COUNT));
+		seq_printf(m, "DC5 -> DC6 count: %d\n",
+			   I915_READ(SKL_CSR_DC5_DC6_COUNT));
+	} else if (IS_BROXTON(dev) && csr->version >= CSR_VERSION(1, 4)) {
+		seq_printf(m, "DC3 -> DC5 count: %d\n",
+			   I915_READ(BXT_CSR_DC3_DC5_COUNT));
+	}
+
+out:
+	seq_printf(m, "program base: 0x%08x\n", I915_READ(CSR_PROGRAM(0)));
+	seq_printf(m, "ssp base: 0x%08x\n", I915_READ(CSR_SSP_BASE));
+	seq_printf(m, "htp: 0x%08x\n", I915_READ(CSR_HTP_SKL));
+
+	intel_runtime_pm_put(dev_priv);
+
+	return 0;
+}
+
 static void intel_seq_print_mode(struct seq_file *m, int tabs,
 				 struct drm_display_mode *mode)
 {
@@ -2946,6 +2997,107 @@
 	return cursor_active(dev, pipe);
 }
 
+static const char *plane_type(enum drm_plane_type type)
+{
+	switch (type) {
+	case DRM_PLANE_TYPE_OVERLAY:
+		return "OVL";
+	case DRM_PLANE_TYPE_PRIMARY:
+		return "PRI";
+	case DRM_PLANE_TYPE_CURSOR:
+		return "CUR";
+	/*
+	 * Deliberately omitting default: to generate compiler warnings
+	 * when a new drm_plane_type gets added.
+	 */
+	}
+
+	return "unknown";
+}
+
+static const char *plane_rotation(unsigned int rotation)
+{
+	static char buf[48];
+	/*
+	 * According to doc only one DRM_ROTATE_ is allowed but this
+	 * will print them all to visualize if the values are misused
+	 */
+	snprintf(buf, sizeof(buf),
+		 "%s%s%s%s%s%s(0x%08x)",
+		 (rotation & BIT(DRM_ROTATE_0)) ? "0 " : "",
+		 (rotation & BIT(DRM_ROTATE_90)) ? "90 " : "",
+		 (rotation & BIT(DRM_ROTATE_180)) ? "180 " : "",
+		 (rotation & BIT(DRM_ROTATE_270)) ? "270 " : "",
+		 (rotation & BIT(DRM_REFLECT_X)) ? "FLIPX " : "",
+		 (rotation & BIT(DRM_REFLECT_Y)) ? "FLIPY " : "",
+		 rotation);
+
+	return buf;
+}
+
+static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc)
+{
+	struct drm_info_node *node = m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct intel_plane *intel_plane;
+
+	for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+		struct drm_plane_state *state;
+		struct drm_plane *plane = &intel_plane->base;
+
+		if (!plane->state) {
+			seq_puts(m, "plane->state is NULL!\n");
+			continue;
+		}
+
+		state = plane->state;
+
+		seq_printf(m, "\t--Plane id %d: type=%s, crtc_pos=%4dx%4d, crtc_size=%4dx%4d, src_pos=%d.%04ux%d.%04u, src_size=%d.%04ux%d.%04u, format=%s, rotation=%s\n",
+			   plane->base.id,
+			   plane_type(intel_plane->base.type),
+			   state->crtc_x, state->crtc_y,
+			   state->crtc_w, state->crtc_h,
+			   (state->src_x >> 16),
+			   ((state->src_x & 0xffff) * 15625) >> 10,
+			   (state->src_y >> 16),
+			   ((state->src_y & 0xffff) * 15625) >> 10,
+			   (state->src_w >> 16),
+			   ((state->src_w & 0xffff) * 15625) >> 10,
+			   (state->src_h >> 16),
+			   ((state->src_h & 0xffff) * 15625) >> 10,
+			   state->fb ? drm_get_format_name(state->fb->pixel_format) : "N/A",
+			   plane_rotation(state->rotation));
+	}
+}
+
+static void intel_scaler_info(struct seq_file *m, struct intel_crtc *intel_crtc)
+{
+	struct intel_crtc_state *pipe_config;
+	int num_scalers = intel_crtc->num_scalers;
+	int i;
+
+	pipe_config = to_intel_crtc_state(intel_crtc->base.state);
+
+	/* Not all platformas have a scaler */
+	if (num_scalers) {
+		seq_printf(m, "\tnum_scalers=%d, scaler_users=%x scaler_id=%d",
+			   num_scalers,
+			   pipe_config->scaler_state.scaler_users,
+			   pipe_config->scaler_state.scaler_id);
+
+		for (i = 0; i < SKL_NUM_SCALERS; i++) {
+			struct intel_scaler *sc =
+					&pipe_config->scaler_state.scalers[i];
+
+			seq_printf(m, ", scalers[%d]: use=%s, mode=%x",
+				   i, yesno(sc->in_use), sc->mode);
+		}
+		seq_puts(m, "\n");
+	} else {
+		seq_puts(m, "\tNo scalers available on this platform\n");
+	}
+}
+
 static int i915_display_info(struct seq_file *m, void *unused)
 {
 	struct drm_info_node *node = m->private;
@@ -2965,10 +3117,12 @@
 
 		pipe_config = to_intel_crtc_state(crtc->base.state);
 
-		seq_printf(m, "CRTC %d: pipe: %c, active=%s (size=%dx%d)\n",
+		seq_printf(m, "CRTC %d: pipe: %c, active=%s, (size=%dx%d), dither=%s, bpp=%d\n",
 			   crtc->base.base.id, pipe_name(crtc->pipe),
 			   yesno(pipe_config->base.active),
-			   pipe_config->pipe_src_w, pipe_config->pipe_src_h);
+			   pipe_config->pipe_src_w, pipe_config->pipe_src_h,
+			   yesno(pipe_config->dither), pipe_config->pipe_bpp);
+
 		if (pipe_config->base.active) {
 			intel_crtc_info(m, crtc);
 
@@ -2978,6 +3132,8 @@
 				   x, y, crtc->base.cursor->state->crtc_w,
 				   crtc->base.cursor->state->crtc_h,
 				   crtc->cursor_addr, yesno(active));
+			intel_scaler_info(m, crtc);
+			intel_plane_info(m, crtc);
 		}
 
 		seq_printf(m, "\tunderrun reporting: cpu=%s pch=%s \n",
@@ -3112,7 +3268,8 @@
 
 	seq_printf(m, "Workarounds applied: %d\n", dev_priv->workarounds.count);
 	for (i = 0; i < dev_priv->workarounds.count; ++i) {
-		u32 addr, mask, value, read;
+		i915_reg_t addr;
+		u32 mask, value, read;
 		bool ok;
 
 		addr = dev_priv->workarounds.reg[i].addr;
@@ -3121,7 +3278,7 @@
 		read = I915_READ(addr);
 		ok = (value & mask) == (read & mask);
 		seq_printf(m, "0x%X: 0x%08X, mask: 0x%08X, read: 0x%08x, status: %s\n",
-			   addr, value, mask, read, ok ? "OK" : "FAIL");
+			   i915_mmio_reg_offset(addr), value, mask, read, ok ? "OK" : "FAIL");
 	}
 
 	intel_runtime_pm_put(dev_priv);
@@ -5025,7 +5182,7 @@
 
 		stat->slice_total++;
 
-		if (IS_SKYLAKE(dev))
+		if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
 			ss_cnt = INTEL_INFO(dev)->subslice_per_slice;
 
 		for (ss = 0; ss < ss_max; ss++) {
@@ -5238,6 +5395,7 @@
 	{"i915_energy_uJ", i915_energy_uJ, 0},
 	{"i915_runtime_pm_status", i915_runtime_pm_status, 0},
 	{"i915_power_domain_info", i915_power_domain_info, 0},
+	{"i915_dmc_info", i915_dmc_info, 0},
 	{"i915_display_info", i915_display_info, 0},
 	{"i915_semaphore_status", i915_semaphore_status, 0},
 	{"i915_shared_dplls_info", i915_shared_dplls_info, 0},
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index b4741d1..a81c766 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -28,7 +28,6 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/async.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
@@ -338,7 +337,7 @@
 		i915_resume_switcheroo(dev);
 		dev->switch_power_state = DRM_SWITCH_POWER_ON;
 	} else {
-		pr_err("switched off\n");
+		pr_info("switched off\n");
 		dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
 		i915_suspend_switcheroo(dev, pmm);
 		dev->switch_power_state = DRM_SWITCH_POWER_OFF;
@@ -396,7 +395,9 @@
 	if (ret)
 		goto cleanup_vga_switcheroo;
 
-	intel_power_domains_init_hw(dev_priv);
+	intel_power_domains_init_hw(dev_priv, false);
+
+	intel_csr_ucode_init(dev_priv);
 
 	ret = intel_irq_install(dev_priv);
 	if (ret)
@@ -437,7 +438,7 @@
 	 * scanning against hotplug events. Hence do this first and ignore the
 	 * tiny window where we will loose hotplug notifactions.
 	 */
-	async_schedule(intel_fbdev_initial_config, dev_priv);
+	intel_fbdev_initial_config_async(dev);
 
 	drm_kms_helper_poll_init(dev);
 
@@ -663,7 +664,8 @@
 	 * supports EU power gating on devices with more than one EU
 	 * pair per subslice.
 	*/
-	info->has_slice_pg = (IS_SKYLAKE(dev) && (info->slice_total > 1));
+	info->has_slice_pg = ((IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) &&
+			       (info->slice_total > 1));
 	info->has_subslice_pg = (IS_BROXTON(dev) && (info->subslice_total > 1));
 	info->has_eu_pg = (info->eu_per_subslice > 2);
 }
@@ -890,7 +892,6 @@
 	spin_lock_init(&dev_priv->mmio_flip_lock);
 	mutex_init(&dev_priv->sb_lock);
 	mutex_init(&dev_priv->modeset_restore_lock);
-	mutex_init(&dev_priv->csr_lock);
 	mutex_init(&dev_priv->av_mutex);
 
 	intel_pm_setup(dev);
@@ -937,9 +938,6 @@
 
 	intel_uncore_init(dev);
 
-	/* Load CSR Firmware for SKL */
-	intel_csr_ucode_init(dev);
-
 	ret = i915_gem_gtt_init(dev);
 	if (ret)
 		goto out_freecsr;
@@ -1113,7 +1111,7 @@
 out_gtt:
 	i915_global_gtt_cleanup(dev);
 out_freecsr:
-	intel_csr_ucode_fini(dev);
+	intel_csr_ucode_fini(dev_priv);
 	intel_uncore_fini(dev);
 	pci_iounmap(dev->pdev, dev_priv->regs);
 put_bridge:
@@ -1131,6 +1129,8 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
 
+	intel_fbdev_fini(dev);
+
 	i915_audio_component_cleanup(dev_priv);
 
 	ret = i915_gem_suspend(dev);
@@ -1153,8 +1153,6 @@
 
 	acpi_video_unregister();
 
-	intel_fbdev_fini(dev);
-
 	drm_vblank_cleanup(dev);
 
 	intel_modeset_cleanup(dev);
@@ -1196,7 +1194,7 @@
 	intel_fbc_cleanup_cfb(dev_priv);
 	i915_gem_cleanup_stolen(dev);
 
-	intel_csr_ucode_fini(dev);
+	intel_csr_ucode_fini(dev_priv);
 
 	intel_teardown_gmbus(dev);
 	intel_teardown_mchbar(dev);
@@ -1264,8 +1262,6 @@
 {
 	struct drm_i915_file_private *file_priv = file->driver_priv;
 
-	if (file_priv && file_priv->bsd_ring)
-		file_priv->bsd_ring = NULL;
 	kfree(file_priv);
 }
 
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 760e0ce..6344dfb 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -383,6 +383,7 @@
 
 static const struct intel_device_info intel_broxton_info = {
 	.is_preliminary = 1,
+	.is_broxton = 1,
 	.gen = 9,
 	.need_gfx_hws = 1, .has_hotplug = 1,
 	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
@@ -394,50 +395,81 @@
 	IVB_CURSOR_OFFSETS,
 };
 
+static const struct intel_device_info intel_kabylake_info = {
+	.is_preliminary = 1,
+	.is_kabylake = 1,
+	.gen = 9,
+	.num_pipes = 3,
+	.need_gfx_hws = 1, .has_hotplug = 1,
+	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
+	.has_llc = 1,
+	.has_ddi = 1,
+	.has_fpga_dbg = 1,
+	.has_fbc = 1,
+	GEN_DEFAULT_PIPEOFFSETS,
+	IVB_CURSOR_OFFSETS,
+};
+
+static const struct intel_device_info intel_kabylake_gt3_info = {
+	.is_preliminary = 1,
+	.is_kabylake = 1,
+	.gen = 9,
+	.num_pipes = 3,
+	.need_gfx_hws = 1, .has_hotplug = 1,
+	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
+	.has_llc = 1,
+	.has_ddi = 1,
+	.has_fpga_dbg = 1,
+	.has_fbc = 1,
+	GEN_DEFAULT_PIPEOFFSETS,
+	IVB_CURSOR_OFFSETS,
+};
+
 /*
  * Make sure any device matches here are from most specific to most
  * general.  For example, since the Quanta match is based on the subsystem
  * and subvendor IDs, we need it to come before the more general IVB
  * PCI ID matches, otherwise we'll use the wrong info struct above.
  */
-#define INTEL_PCI_IDS \
-	INTEL_I830_IDS(&intel_i830_info),	\
-	INTEL_I845G_IDS(&intel_845g_info),	\
-	INTEL_I85X_IDS(&intel_i85x_info),	\
-	INTEL_I865G_IDS(&intel_i865g_info),	\
-	INTEL_I915G_IDS(&intel_i915g_info),	\
-	INTEL_I915GM_IDS(&intel_i915gm_info),	\
-	INTEL_I945G_IDS(&intel_i945g_info),	\
-	INTEL_I945GM_IDS(&intel_i945gm_info),	\
-	INTEL_I965G_IDS(&intel_i965g_info),	\
-	INTEL_G33_IDS(&intel_g33_info),		\
-	INTEL_I965GM_IDS(&intel_i965gm_info),	\
-	INTEL_GM45_IDS(&intel_gm45_info), 	\
-	INTEL_G45_IDS(&intel_g45_info), 	\
-	INTEL_PINEVIEW_IDS(&intel_pineview_info),	\
-	INTEL_IRONLAKE_D_IDS(&intel_ironlake_d_info),	\
-	INTEL_IRONLAKE_M_IDS(&intel_ironlake_m_info),	\
-	INTEL_SNB_D_IDS(&intel_sandybridge_d_info),	\
-	INTEL_SNB_M_IDS(&intel_sandybridge_m_info),	\
-	INTEL_IVB_Q_IDS(&intel_ivybridge_q_info), /* must be first IVB */ \
-	INTEL_IVB_M_IDS(&intel_ivybridge_m_info),	\
-	INTEL_IVB_D_IDS(&intel_ivybridge_d_info),	\
-	INTEL_HSW_D_IDS(&intel_haswell_d_info), \
-	INTEL_HSW_M_IDS(&intel_haswell_m_info), \
-	INTEL_VLV_M_IDS(&intel_valleyview_m_info),	\
-	INTEL_VLV_D_IDS(&intel_valleyview_d_info),	\
-	INTEL_BDW_GT12M_IDS(&intel_broadwell_m_info),	\
-	INTEL_BDW_GT12D_IDS(&intel_broadwell_d_info),	\
-	INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info),	\
-	INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info), \
-	INTEL_CHV_IDS(&intel_cherryview_info),	\
-	INTEL_SKL_GT1_IDS(&intel_skylake_info),	\
-	INTEL_SKL_GT2_IDS(&intel_skylake_info),	\
-	INTEL_SKL_GT3_IDS(&intel_skylake_gt3_info),	\
-	INTEL_BXT_IDS(&intel_broxton_info)
-
-static const struct pci_device_id pciidlist[] = {		/* aka */
-	INTEL_PCI_IDS,
+static const struct pci_device_id pciidlist[] = {
+	INTEL_I830_IDS(&intel_i830_info),
+	INTEL_I845G_IDS(&intel_845g_info),
+	INTEL_I85X_IDS(&intel_i85x_info),
+	INTEL_I865G_IDS(&intel_i865g_info),
+	INTEL_I915G_IDS(&intel_i915g_info),
+	INTEL_I915GM_IDS(&intel_i915gm_info),
+	INTEL_I945G_IDS(&intel_i945g_info),
+	INTEL_I945GM_IDS(&intel_i945gm_info),
+	INTEL_I965G_IDS(&intel_i965g_info),
+	INTEL_G33_IDS(&intel_g33_info),
+	INTEL_I965GM_IDS(&intel_i965gm_info),
+	INTEL_GM45_IDS(&intel_gm45_info),
+	INTEL_G45_IDS(&intel_g45_info),
+	INTEL_PINEVIEW_IDS(&intel_pineview_info),
+	INTEL_IRONLAKE_D_IDS(&intel_ironlake_d_info),
+	INTEL_IRONLAKE_M_IDS(&intel_ironlake_m_info),
+	INTEL_SNB_D_IDS(&intel_sandybridge_d_info),
+	INTEL_SNB_M_IDS(&intel_sandybridge_m_info),
+	INTEL_IVB_Q_IDS(&intel_ivybridge_q_info), /* must be first IVB */
+	INTEL_IVB_M_IDS(&intel_ivybridge_m_info),
+	INTEL_IVB_D_IDS(&intel_ivybridge_d_info),
+	INTEL_HSW_D_IDS(&intel_haswell_d_info),
+	INTEL_HSW_M_IDS(&intel_haswell_m_info),
+	INTEL_VLV_M_IDS(&intel_valleyview_m_info),
+	INTEL_VLV_D_IDS(&intel_valleyview_d_info),
+	INTEL_BDW_GT12M_IDS(&intel_broadwell_m_info),
+	INTEL_BDW_GT12D_IDS(&intel_broadwell_d_info),
+	INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info),
+	INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info),
+	INTEL_CHV_IDS(&intel_cherryview_info),
+	INTEL_SKL_GT1_IDS(&intel_skylake_info),
+	INTEL_SKL_GT2_IDS(&intel_skylake_info),
+	INTEL_SKL_GT3_IDS(&intel_skylake_gt3_info),
+	INTEL_BXT_IDS(&intel_broxton_info),
+	INTEL_KBL_GT1_IDS(&intel_kabylake_info),
+	INTEL_KBL_GT2_IDS(&intel_kabylake_info),
+	INTEL_KBL_GT3_IDS(&intel_kabylake_gt3_info),
+	INTEL_KBL_GT4_IDS(&intel_kabylake_gt3_info),
 	{0, 0, 0}
 };
 
@@ -463,7 +495,7 @@
 	} else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
 		ret = PCH_LPT;
 		DRM_DEBUG_KMS("Assuming LynxPoint PCH\n");
-	} else if (IS_SKYLAKE(dev)) {
+	} else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
 		ret = PCH_SPT;
 		DRM_DEBUG_KMS("Assuming SunrisePoint PCH\n");
 	}
@@ -526,11 +558,13 @@
 			} else if (id == INTEL_PCH_SPT_DEVICE_ID_TYPE) {
 				dev_priv->pch_type = PCH_SPT;
 				DRM_DEBUG_KMS("Found SunrisePoint PCH\n");
-				WARN_ON(!IS_SKYLAKE(dev));
+				WARN_ON(!IS_SKYLAKE(dev) &&
+					!IS_KABYLAKE(dev));
 			} else if (id == INTEL_PCH_SPT_LP_DEVICE_ID_TYPE) {
 				dev_priv->pch_type = PCH_SPT;
 				DRM_DEBUG_KMS("Found SunrisePoint LP PCH\n");
-				WARN_ON(!IS_SKYLAKE(dev));
+				WARN_ON(!IS_SKYLAKE(dev) &&
+					!IS_KABYLAKE(dev));
 			} else if (id == INTEL_PCH_P2X_DEVICE_ID_TYPE) {
 				dev_priv->pch_type = intel_virt_detect_pch(dev);
 			} else
@@ -570,26 +604,6 @@
 	return true;
 }
 
-void i915_firmware_load_error_print(const char *fw_path, int err)
-{
-	DRM_ERROR("failed to load firmware %s (%d)\n", fw_path, err);
-
-	/*
-	 * If the reason is not known assume -ENOENT since that's the most
-	 * usual failure mode.
-	 */
-	if (!err)
-		err = -ENOENT;
-
-	if (!(IS_BUILTIN(CONFIG_DRM_I915) && err == -ENOENT))
-		return;
-
-	DRM_ERROR(
-	  "The driver is built-in, so to load the firmware you need to\n"
-	  "include it either in the kernel (see CONFIG_EXTRA_FIRMWARE) or\n"
-	  "in your initrd/initramfs image.\n");
-}
-
 static void intel_suspend_encoders(struct drm_i915_private *dev_priv)
 {
 	struct drm_device *dev = dev_priv->dev;
@@ -608,7 +622,6 @@
 static int intel_suspend_complete(struct drm_i915_private *dev_priv);
 static int vlv_resume_prepare(struct drm_i915_private *dev_priv,
 			      bool rpm_resume);
-static int skl_resume_prepare(struct drm_i915_private *dev_priv);
 static int bxt_resume_prepare(struct drm_i915_private *dev_priv);
 
 
@@ -679,6 +692,9 @@
 
 	intel_display_set_init_power(dev_priv, false);
 
+	if (HAS_CSR(dev_priv))
+		flush_work(&dev_priv->csr.work);
+
 	return 0;
 }
 
@@ -687,10 +703,13 @@
 	struct drm_i915_private *dev_priv = drm_dev->dev_private;
 	int ret;
 
+	intel_power_domains_suspend(dev_priv);
+
 	ret = intel_suspend_complete(dev_priv);
 
 	if (ret) {
 		DRM_ERROR("Suspend complete failed: %d\n", ret);
+		intel_power_domains_init_hw(dev_priv, true);
 
 		return ret;
 	}
@@ -838,13 +857,11 @@
 
 	if (IS_BROXTON(dev))
 		ret = bxt_resume_prepare(dev_priv);
-	else if (IS_SKYLAKE(dev_priv))
-		ret = skl_resume_prepare(dev_priv);
 	else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
 		hsw_disable_pc8(dev_priv);
 
 	intel_uncore_sanitize(dev);
-	intel_power_domains_init_hw(dev_priv);
+	intel_power_domains_init_hw(dev_priv, true);
 
 	return ret;
 }
@@ -1051,15 +1068,6 @@
 	return i915_drm_resume(drm_dev);
 }
 
-static int skl_suspend_complete(struct drm_i915_private *dev_priv)
-{
-	/* Enabling DC6 is not a hard requirement to enter runtime D3 */
-
-	skl_uninit_cdclk(dev_priv);
-
-	return 0;
-}
-
 static int hsw_suspend_complete(struct drm_i915_private *dev_priv)
 {
 	hsw_enable_pc8(dev_priv);
@@ -1099,16 +1107,6 @@
 	return 0;
 }
 
-static int skl_resume_prepare(struct drm_i915_private *dev_priv)
-{
-	struct drm_device *dev = dev_priv->dev;
-
-	skl_init_cdclk(dev_priv);
-	intel_csr_load_program(dev);
-
-	return 0;
-}
-
 /*
  * Save all Gunit registers that may be lost after a D3 and a subsequent
  * S0i[R123] transition. The list of registers needing a save/restore is
@@ -1572,8 +1570,6 @@
 
 	if (IS_BROXTON(dev))
 		ret = bxt_resume_prepare(dev_priv);
-	else if (IS_SKYLAKE(dev))
-		ret = skl_resume_prepare(dev_priv);
 	else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
 		hsw_disable_pc8(dev_priv);
 	else if (IS_VALLEYVIEW(dev_priv))
@@ -1616,8 +1612,6 @@
 
 	if (IS_BROXTON(dev_priv))
 		ret = bxt_suspend_complete(dev_priv);
-	else if (IS_SKYLAKE(dev_priv))
-		ret = skl_suspend_complete(dev_priv);
 	else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
 		ret = hsw_suspend_complete(dev_priv);
 	else if (IS_VALLEYVIEW(dev_priv))
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f4af19a..e6ab465 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -57,7 +57,7 @@
 
 #define DRIVER_NAME		"i915"
 #define DRIVER_DESC		"Intel Graphics"
-#define DRIVER_DATE		"20151010"
+#define DRIVER_DATE		"20151120"
 
 #undef WARN_ON
 /* Many gcc seem to no see through this and fall over :( */
@@ -180,15 +180,11 @@
 	POWER_DOMAIN_TRANSCODER_B,
 	POWER_DOMAIN_TRANSCODER_C,
 	POWER_DOMAIN_TRANSCODER_EDP,
-	POWER_DOMAIN_PORT_DDI_A_2_LANES,
-	POWER_DOMAIN_PORT_DDI_A_4_LANES,
-	POWER_DOMAIN_PORT_DDI_B_2_LANES,
-	POWER_DOMAIN_PORT_DDI_B_4_LANES,
-	POWER_DOMAIN_PORT_DDI_C_2_LANES,
-	POWER_DOMAIN_PORT_DDI_C_4_LANES,
-	POWER_DOMAIN_PORT_DDI_D_2_LANES,
-	POWER_DOMAIN_PORT_DDI_D_4_LANES,
-	POWER_DOMAIN_PORT_DDI_E_2_LANES,
+	POWER_DOMAIN_PORT_DDI_A_LANES,
+	POWER_DOMAIN_PORT_DDI_B_LANES,
+	POWER_DOMAIN_PORT_DDI_C_LANES,
+	POWER_DOMAIN_PORT_DDI_D_LANES,
+	POWER_DOMAIN_PORT_DDI_E_LANES,
 	POWER_DOMAIN_PORT_DSI,
 	POWER_DOMAIN_PORT_CRT,
 	POWER_DOMAIN_PORT_OTHER,
@@ -200,6 +196,7 @@
 	POWER_DOMAIN_AUX_C,
 	POWER_DOMAIN_AUX_D,
 	POWER_DOMAIN_GMBUS,
+	POWER_DOMAIN_MODESET,
 	POWER_DOMAIN_INIT,
 
 	POWER_DOMAIN_NUM,
@@ -289,7 +286,7 @@
 	list_for_each_entry(intel_plane,				\
 			    &(dev)->mode_config.plane_list,		\
 			    base.head)					\
-		if ((intel_plane)->pipe == (intel_crtc)->pipe)
+		for_each_if ((intel_plane)->pipe == (intel_crtc)->pipe)
 
 #define for_each_intel_crtc(dev, intel_crtc) \
 	list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head)
@@ -306,15 +303,15 @@
 
 #define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \
 	list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \
-		if ((intel_encoder)->base.crtc == (__crtc))
+		for_each_if ((intel_encoder)->base.crtc == (__crtc))
 
 #define for_each_connector_on_encoder(dev, __encoder, intel_connector) \
 	list_for_each_entry((intel_connector), &(dev)->mode_config.connector_list, base.head) \
-		if ((intel_connector)->base.encoder == (__encoder))
+		for_each_if ((intel_connector)->base.encoder == (__encoder))
 
 #define for_each_power_domain(domain, mask)				\
 	for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++)	\
-		if ((1 << (domain)) & (mask))
+		for_each_if ((1 << (domain)) & (mask))
 
 struct drm_i915_private;
 struct i915_mm_struct;
@@ -631,11 +628,9 @@
 			  int target, int refclk,
 			  struct dpll *match_clock,
 			  struct dpll *best_clock);
+	int (*compute_pipe_wm)(struct intel_crtc *crtc,
+			       struct drm_atomic_state *state);
 	void (*update_wm)(struct drm_crtc *crtc);
-	void (*update_sprite_wm)(struct drm_plane *plane,
-				 struct drm_crtc *crtc,
-				 uint32_t sprite_width, uint32_t sprite_height,
-				 int pixel_size, bool enable, bool scaled);
 	int (*modeset_calc_cdclk)(struct drm_atomic_state *state);
 	void (*modeset_commit_cdclk)(struct drm_atomic_state *state);
 	/* Returns the active state of the crtc, and if the crtc is active,
@@ -693,18 +688,18 @@
 	void (*force_wake_put)(struct drm_i915_private *dev_priv,
 							enum forcewake_domains domains);
 
-	uint8_t  (*mmio_readb)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
-	uint16_t (*mmio_readw)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
-	uint32_t (*mmio_readl)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
-	uint64_t (*mmio_readq)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
+	uint8_t  (*mmio_readb)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace);
+	uint16_t (*mmio_readw)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace);
+	uint32_t (*mmio_readl)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace);
+	uint64_t (*mmio_readq)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace);
 
-	void (*mmio_writeb)(struct drm_i915_private *dev_priv, off_t offset,
+	void (*mmio_writeb)(struct drm_i915_private *dev_priv, i915_reg_t r,
 				uint8_t val, bool trace);
-	void (*mmio_writew)(struct drm_i915_private *dev_priv, off_t offset,
+	void (*mmio_writew)(struct drm_i915_private *dev_priv, i915_reg_t r,
 				uint16_t val, bool trace);
-	void (*mmio_writel)(struct drm_i915_private *dev_priv, off_t offset,
+	void (*mmio_writel)(struct drm_i915_private *dev_priv, i915_reg_t r,
 				uint32_t val, bool trace);
-	void (*mmio_writeq)(struct drm_i915_private *dev_priv, off_t offset,
+	void (*mmio_writeq)(struct drm_i915_private *dev_priv, i915_reg_t r,
 				uint64_t val, bool trace);
 };
 
@@ -721,11 +716,11 @@
 		enum forcewake_domain_id id;
 		unsigned wake_count;
 		struct timer_list timer;
-		u32 reg_set;
+		i915_reg_t reg_set;
 		u32 val_set;
 		u32 val_clear;
-		u32 reg_ack;
-		u32 reg_post;
+		i915_reg_t reg_ack;
+		i915_reg_t reg_post;
 		u32 val_reset;
 	} fw_domain[FW_DOMAIN_ID_COUNT];
 };
@@ -735,25 +730,24 @@
 	for ((i__) = 0, (domain__) = &(dev_priv__)->uncore.fw_domain[0]; \
 	     (i__) < FW_DOMAIN_ID_COUNT; \
 	     (i__)++, (domain__) = &(dev_priv__)->uncore.fw_domain[i__]) \
-		if (((mask__) & (dev_priv__)->uncore.fw_domains) & (1 << (i__)))
+		for_each_if (((mask__) & (dev_priv__)->uncore.fw_domains) & (1 << (i__)))
 
 #define for_each_fw_domain(domain__, dev_priv__, i__) \
 	for_each_fw_domain_mask(domain__, FORCEWAKE_ALL, dev_priv__, i__)
 
-enum csr_state {
-	FW_UNINITIALIZED = 0,
-	FW_LOADED,
-	FW_FAILED
-};
+#define CSR_VERSION(major, minor)	((major) << 16 | (minor))
+#define CSR_VERSION_MAJOR(version)	((version) >> 16)
+#define CSR_VERSION_MINOR(version)	((version) & 0xffff)
 
 struct intel_csr {
+	struct work_struct work;
 	const char *fw_path;
 	uint32_t *dmc_payload;
 	uint32_t dmc_fw_size;
+	uint32_t version;
 	uint32_t mmio_count;
-	uint32_t mmioaddr[8];
+	i915_reg_t mmioaddr[8];
 	uint32_t mmiodata[8];
-	enum csr_state state;
 };
 
 #define DEV_INFO_FOR_EACH_FLAG(func, sep) \
@@ -771,6 +765,8 @@
 	func(is_valleyview) sep \
 	func(is_haswell) sep \
 	func(is_skylake) sep \
+	func(is_broxton) sep \
+	func(is_kabylake) sep \
 	func(is_preliminary) sep \
 	func(has_fbc) sep \
 	func(has_pipe_cxsr) sep \
@@ -929,24 +925,7 @@
 		struct drm_framebuffer *fb;
 	} *fbc_work;
 
-	enum no_fbc_reason {
-		FBC_OK, /* FBC is enabled */
-		FBC_UNSUPPORTED, /* FBC is not supported by this chipset */
-		FBC_NO_OUTPUT, /* no outputs enabled to compress */
-		FBC_STOLEN_TOO_SMALL, /* not enough space for buffers */
-		FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */
-		FBC_MODE_TOO_LARGE, /* mode too large for compression */
-		FBC_BAD_PLANE, /* fbc not supported on plane */
-		FBC_NOT_TILED, /* buffer not tiled */
-		FBC_MULTIPLE_PIPES, /* more than one pipe active */
-		FBC_MODULE_PARAM,
-		FBC_CHIP_DEFAULT, /* disabled by default on this chip */
-		FBC_ROTATION, /* rotation is not supported */
-		FBC_IN_DBG_MASTER, /* kernel debugger is active */
-		FBC_BAD_STRIDE, /* stride is not supported */
-		FBC_PIXEL_RATE, /* pixel rate is too big */
-		FBC_PIXEL_FORMAT /* pixel format is invalid */
-	} no_fbc_reason;
+	const char *no_fbc_reason;
 
 	bool (*fbc_enabled)(struct drm_i915_private *dev_priv);
 	void (*enable_fbc)(struct intel_crtc *crtc);
@@ -1020,7 +999,7 @@
 	struct i2c_adapter adapter;
 	u32 force_bit;
 	u32 reg0;
-	u32 gpio_reg;
+	i915_reg_t gpio_reg;
 	struct i2c_algo_bit_data bit_algo;
 	struct drm_i915_private *dev_priv;
 };
@@ -1669,7 +1648,7 @@
 };
 
 struct i915_wa_reg {
-	u32 addr;
+	i915_reg_t addr;
 	u32 value;
 	/* bitmask representing WA bits */
 	u32 mask;
@@ -1698,6 +1677,13 @@
 	struct drm_i915_gem_request     *request;
 };
 
+/* used in computing the new watermarks state */
+struct intel_wm_config {
+	unsigned int num_pipes_active;
+	bool sprites_enabled;
+	bool sprites_scaled;
+};
+
 struct drm_i915_private {
 	struct drm_device *dev;
 	struct kmem_cache *objects;
@@ -1718,9 +1704,6 @@
 
 	struct intel_csr csr;
 
-	/* Display CSR-related protection */
-	struct mutex csr_lock;
-
 	struct intel_gmbus gmbus[GMBUS_NUM_PINS];
 
 	/** gmbus_mutex protects against concurrent usage of the single hw gmbus
@@ -1735,6 +1718,8 @@
 	/* MMIO base address for MIPI regs */
 	uint32_t mipi_mmio_base;
 
+	uint32_t psr_mmio_base;
+
 	wait_queue_head_t gmbus_wait_queue;
 
 	struct pci_dev *bridge_dev;
@@ -1922,6 +1907,9 @@
 		 */
 		uint16_t skl_latency[8];
 
+		/* Committed wm config */
+		struct intel_wm_config config;
+
 		/*
 		 * The skl_wm_values structure is a bit too big for stack
 		 * allocation, so we keep the staging struct where we store
@@ -1956,6 +1944,8 @@
 	/* perform PHY state sanity checks? */
 	bool chv_phy_assert[2];
 
+	struct intel_encoder *dig_port_map[I915_MAX_PORTS];
+
 	/*
 	 * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
 	 * will be rejected. Instead look for a better place.
@@ -1980,7 +1970,7 @@
 /* Iterate over initialised rings */
 #define for_each_ring(ring__, dev_priv__, i__) \
 	for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \
-		if (((ring__) = &(dev_priv__)->ring[(i__)]), intel_ring_initialized((ring__)))
+		for_each_if ((((ring__) = &(dev_priv__)->ring[(i__)]), intel_ring_initialized((ring__))))
 
 enum hdmi_force_audio {
 	HDMI_AUDIO_OFF_DVI = -2,	/* no aux data for HDMI-DVI converter */
@@ -2445,6 +2435,15 @@
 #define INTEL_DEVID(p)	(INTEL_INFO(p)->device_id)
 #define INTEL_REVID(p)	(__I915__(p)->dev->pdev->revision)
 
+#define REVID_FOREVER		0xff
+/*
+ * Return true if revision is in range [since,until] inclusive.
+ *
+ * Use 0 for open-ended since, and REVID_FOREVER for open-ended until.
+ */
+#define IS_REVID(p, since, until) \
+	(INTEL_REVID(p) >= (since) && INTEL_REVID(p) <= (until))
+
 #define IS_I830(dev)		(INTEL_DEVID(dev) == 0x3577)
 #define IS_845G(dev)		(INTEL_DEVID(dev) == 0x2562)
 #define IS_I85X(dev)		(INTEL_INFO(dev)->is_i85x)
@@ -2471,7 +2470,8 @@
 #define IS_HASWELL(dev)	(INTEL_INFO(dev)->is_haswell)
 #define IS_BROADWELL(dev)	(!INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev))
 #define IS_SKYLAKE(dev)	(INTEL_INFO(dev)->is_skylake)
-#define IS_BROXTON(dev)	(!INTEL_INFO(dev)->is_skylake && IS_GEN9(dev))
+#define IS_BROXTON(dev)		(INTEL_INFO(dev)->is_broxton)
+#define IS_KABYLAKE(dev)	(INTEL_INFO(dev)->is_kabylake)
 #define IS_MOBILE(dev)		(INTEL_INFO(dev)->is_mobile)
 #define IS_HSW_EARLY_SDV(dev)	(IS_HASWELL(dev) && \
 				 (INTEL_DEVID(dev) & 0xFF00) == 0x0C00)
@@ -2506,16 +2506,21 @@
 
 #define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary)
 
-#define SKL_REVID_A0		(0x0)
-#define SKL_REVID_B0		(0x1)
-#define SKL_REVID_C0		(0x2)
-#define SKL_REVID_D0		(0x3)
-#define SKL_REVID_E0		(0x4)
-#define SKL_REVID_F0		(0x5)
+#define SKL_REVID_A0		0x0
+#define SKL_REVID_B0		0x1
+#define SKL_REVID_C0		0x2
+#define SKL_REVID_D0		0x3
+#define SKL_REVID_E0		0x4
+#define SKL_REVID_F0		0x5
 
-#define BXT_REVID_A0		(0x0)
-#define BXT_REVID_B0		(0x3)
-#define BXT_REVID_C0		(0x9)
+#define IS_SKL_REVID(p, since, until) (IS_SKYLAKE(p) && IS_REVID(p, since, until))
+
+#define BXT_REVID_A0		0x0
+#define BXT_REVID_A1		0x1
+#define BXT_REVID_B0		0x3
+#define BXT_REVID_C0		0x9
+
+#define IS_BXT_REVID(p, since, until) (IS_BROXTON(p) && IS_REVID(p, since, until))
 
 /*
  * The genX designation typically refers to the render engine, so render
@@ -2587,10 +2592,10 @@
 #define HAS_FPGA_DBG_UNCLAIMED(dev)	(INTEL_INFO(dev)->has_fpga_dbg)
 #define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev) || \
 				 IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev) || \
-				 IS_SKYLAKE(dev))
+				 IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
 #define HAS_RUNTIME_PM(dev)	(IS_GEN6(dev) || IS_HASWELL(dev) || \
 				 IS_BROADWELL(dev) || IS_VALLEYVIEW(dev) || \
-				 IS_SKYLAKE(dev))
+				 IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
 #define HAS_RC6(dev)		(INTEL_INFO(dev)->gen >= 6)
 #define HAS_RC6p(dev)		(INTEL_INFO(dev)->gen == 6 || IS_IVYBRIDGE(dev))
 
@@ -2650,6 +2655,7 @@
 	int panel_use_ssc;
 	int vbt_sdvo_panel_type;
 	int enable_rc6;
+	int enable_dc;
 	int enable_fbc;
 	int enable_ppgtt;
 	int enable_execlists;
@@ -2698,7 +2704,6 @@
 extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
 extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
 int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on);
-void i915_firmware_load_error_print(const char *fw_path, int err);
 
 /* intel_hotplug.c */
 void intel_hpd_irq_handler(struct drm_device *dev, u32 pin_mask, u32 long_mask);
@@ -3008,8 +3013,6 @@
 int __must_check
 i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
 				     u32 alignment,
-				     struct intel_engine_cs *pipelined,
-				     struct drm_i915_gem_request **pipelined_request,
 				     const struct i915_ggtt_view *view);
 void i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj,
 					      const struct i915_ggtt_view *view);
@@ -3364,7 +3367,6 @@
 extern void intel_set_memory_cxsr(struct drm_i915_private *dev_priv,
 				  bool enable);
 extern void intel_detect_pch(struct drm_device *dev);
-extern int intel_trans_dp_port_sel(struct drm_crtc *crtc);
 extern int intel_enable_rc6(const struct drm_device *dev);
 
 extern bool i915_semaphore_is_enabled(struct drm_device *dev);
@@ -3447,6 +3449,32 @@
 #define POSTING_READ(reg)	(void)I915_READ_NOTRACE(reg)
 #define POSTING_READ16(reg)	(void)I915_READ16_NOTRACE(reg)
 
+#define __raw_read(x, s) \
+static inline uint##x##_t __raw_i915_read##x(struct drm_i915_private *dev_priv, \
+					     i915_reg_t reg) \
+{ \
+	return read##s(dev_priv->regs + i915_mmio_reg_offset(reg)); \
+}
+
+#define __raw_write(x, s) \
+static inline void __raw_i915_write##x(struct drm_i915_private *dev_priv, \
+				       i915_reg_t reg, uint##x##_t val) \
+{ \
+	write##s(val, dev_priv->regs + i915_mmio_reg_offset(reg)); \
+}
+__raw_read(8, b)
+__raw_read(16, w)
+__raw_read(32, l)
+__raw_read(64, q)
+
+__raw_write(8, b)
+__raw_write(16, w)
+__raw_write(32, l)
+__raw_write(64, q)
+
+#undef __raw_read
+#undef __raw_write
+
 /* These are untraced mmio-accessors that are only valid to be used inside
  * criticial sections inside IRQ handlers where forcewake is explicitly
  * controlled.
@@ -3454,8 +3482,8 @@
  * Note: Should only be used between intel_uncore_forcewake_irqlock() and
  * intel_uncore_forcewake_irqunlock().
  */
-#define I915_READ_FW(reg__) readl(dev_priv->regs + (reg__))
-#define I915_WRITE_FW(reg__, val__) writel(val__, dev_priv->regs + (reg__))
+#define I915_READ_FW(reg__) __raw_i915_read32(dev_priv, (reg__))
+#define I915_WRITE_FW(reg__, val__) __raw_i915_write32(dev_priv, (reg__), (val__))
 #define POSTING_READ_FW(reg__) (void)I915_READ_FW(reg__)
 
 /* "Broadcast RGB" property */
@@ -3463,7 +3491,7 @@
 #define INTEL_BROADCAST_RGB_FULL 1
 #define INTEL_BROADCAST_RGB_LIMITED 2
 
-static inline uint32_t i915_vgacntrl_reg(struct drm_device *dev)
+static inline i915_reg_t i915_vgacntrl_reg(struct drm_device *dev)
 {
 	if (IS_VALLEYVIEW(dev))
 		return VLV_VGACNTRL;
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index f56af0a..262020f 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2797,6 +2797,8 @@
 static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
 					struct intel_engine_cs *ring)
 {
+	struct intel_ringbuffer *buffer;
+
 	while (!list_empty(&ring->active_list)) {
 		struct drm_i915_gem_object *obj;
 
@@ -2812,18 +2814,23 @@
 	 * are the ones that keep the context and ringbuffer backing objects
 	 * pinned in place.
 	 */
-	while (!list_empty(&ring->execlist_queue)) {
-		struct drm_i915_gem_request *submit_req;
 
-		submit_req = list_first_entry(&ring->execlist_queue,
-				struct drm_i915_gem_request,
-				execlist_link);
-		list_del(&submit_req->execlist_link);
+	if (i915.enable_execlists) {
+		spin_lock_irq(&ring->execlist_lock);
+		while (!list_empty(&ring->execlist_queue)) {
+			struct drm_i915_gem_request *submit_req;
 
-		if (submit_req->ctx != ring->default_context)
-			intel_lr_context_unpin(submit_req);
+			submit_req = list_first_entry(&ring->execlist_queue,
+					struct drm_i915_gem_request,
+					execlist_link);
+			list_del(&submit_req->execlist_link);
 
-		i915_gem_request_unreference(submit_req);
+			if (submit_req->ctx != ring->default_context)
+				intel_lr_context_unpin(submit_req);
+
+			i915_gem_request_unreference(submit_req);
+		}
+		spin_unlock_irq(&ring->execlist_lock);
 	}
 
 	/*
@@ -2842,6 +2849,18 @@
 
 		i915_gem_request_retire(request);
 	}
+
+	/* Having flushed all requests from all queues, we know that all
+	 * ringbuffers must now be empty. However, since we do not reclaim
+	 * all space when retiring the request (to prevent HEADs colliding
+	 * with rapid ringbuffer wraparound) the amount of available space
+	 * upon reset is less than when we start. Do one more pass over
+	 * all the ringbuffers to reset last_retired_head.
+	 */
+	list_for_each_entry(buffer, &ring->buffers, link) {
+		buffer->last_retired_head = buffer->tail;
+		intel_ring_update_space(buffer);
+	}
 }
 
 void i915_gem_reset(struct drm_device *dev)
@@ -3886,7 +3905,7 @@
 		 * cacheline, whereas normally such cachelines would get
 		 * invalidated.
 		 */
-		if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0)
+		if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
 			return -ENODEV;
 
 		level = I915_CACHE_LLC;
@@ -3929,17 +3948,11 @@
 int
 i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
 				     u32 alignment,
-				     struct intel_engine_cs *pipelined,
-				     struct drm_i915_gem_request **pipelined_request,
 				     const struct i915_ggtt_view *view)
 {
 	u32 old_read_domains, old_write_domain;
 	int ret;
 
-	ret = i915_gem_object_sync(obj, pipelined, pipelined_request);
-	if (ret)
-		return ret;
-
 	/* Mark the pin_display early so that we account for the
 	 * display coherency whilst setting up the cache domains.
 	 */
@@ -4541,10 +4554,8 @@
 {
 	struct i915_vma *vma;
 	list_for_each_entry(vma, &obj->vma_list, vma_link) {
-		if (i915_is_ggtt(vma->vm) &&
-		    vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
-			continue;
-		if (vma->vm == vm)
+		if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL &&
+		    vma->vm == vm)
 			return vma;
 	}
 	return NULL;
@@ -4633,7 +4644,6 @@
 	struct intel_engine_cs *ring = req->ring;
 	struct drm_device *dev = ring->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 reg_base = GEN7_L3LOG_BASE + (slice * 0x200);
 	u32 *remap_info = dev_priv->l3_parity.remap_info[slice];
 	int i, ret;
 
@@ -4649,10 +4659,10 @@
 	 * here because no other code should access these registers other than
 	 * at initialization time.
 	 */
-	for (i = 0; i < GEN7_L3LOG_SIZE; i += 4) {
+	for (i = 0; i < GEN7_L3LOG_SIZE / 4; i++) {
 		intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
-		intel_ring_emit(ring, reg_base + i);
-		intel_ring_emit(ring, remap_info[i/4]);
+		intel_ring_emit_reg(ring, GEN7_L3LOG(slice, i));
+		intel_ring_emit(ring, remap_info[i]);
 	}
 
 	intel_ring_advance(ring);
@@ -4820,18 +4830,9 @@
 	if (HAS_GUC_UCODE(dev)) {
 		ret = intel_guc_ucode_load(dev);
 		if (ret) {
-			/*
-			 * If we got an error and GuC submission is enabled, map
-			 * the error to -EIO so the GPU will be declared wedged.
-			 * OTOH, if we didn't intend to use the GuC anyway, just
-			 * discard the error and carry on.
-			 */
-			DRM_ERROR("Failed to initialize GuC, error %d%s\n", ret,
-				  i915.enable_guc_submission ? "" :
-				  " (ignored)");
-			ret = i915.enable_guc_submission ? -EIO : 0;
-			if (ret)
-				goto out;
+			DRM_ERROR("Failed to initialize GuC, error %d\n", ret);
+			ret = -EIO;
+			goto out;
 		}
 	}
 
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 02ceb7a..43761c5 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -554,7 +554,7 @@
 				if (signaller == ring)
 					continue;
 
-				intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base));
+				intel_ring_emit_reg(ring, RING_PSMI_CTL(signaller->mmio_base));
 				intel_ring_emit(ring, _MASKED_BIT_ENABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
 			}
 		}
@@ -579,7 +579,7 @@
 				if (signaller == ring)
 					continue;
 
-				intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base));
+				intel_ring_emit_reg(ring, RING_PSMI_CTL(signaller->mmio_base));
 				intel_ring_emit(ring, _MASKED_BIT_DISABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
 			}
 		}
@@ -923,6 +923,14 @@
 	case I915_CONTEXT_PARAM_NO_ZEROMAP:
 		args->value = ctx->flags & CONTEXT_NO_ZEROMAP;
 		break;
+	case I915_CONTEXT_PARAM_GTT_SIZE:
+		if (ctx->ppgtt)
+			args->value = ctx->ppgtt->base.total;
+		else if (to_i915(dev)->mm.aliasing_ppgtt)
+			args->value = to_i915(dev)->mm.aliasing_ppgtt->base.total;
+		else
+			args->value = to_i915(dev)->gtt.base.total;
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 6ed7d63a..a4c243c 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -1114,7 +1114,7 @@
 
 	for (i = 0; i < 4; i++) {
 		intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
-		intel_ring_emit(ring, GEN7_SO_WRITE_OFFSET(i));
+		intel_ring_emit_reg(ring, GEN7_SO_WRITE_OFFSET(i));
 		intel_ring_emit(ring, 0);
 	}
 
@@ -1241,7 +1241,7 @@
 
 		intel_ring_emit(ring, MI_NOOP);
 		intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
-		intel_ring_emit(ring, INSTPM);
+		intel_ring_emit_reg(ring, INSTPM);
 		intel_ring_emit(ring, instp_mask << 16 | instp_mode);
 		intel_ring_advance(ring);
 
diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c
index f010391..5981985 100644
--- a/drivers/gpu/drm/i915/i915_gem_fence.c
+++ b/drivers/gpu/drm/i915/i915_gem_fence.c
@@ -59,7 +59,7 @@
 				 struct drm_i915_gem_object *obj)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	int fence_reg_lo, fence_reg_hi;
+	i915_reg_t fence_reg_lo, fence_reg_hi;
 	int fence_pitch_shift;
 
 	if (INTEL_INFO(dev)->gen >= 6) {
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 86c7500..f4cd01df 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -24,6 +24,7 @@
  */
 
 #include <linux/seq_file.h>
+#include <linux/stop_machine.h>
 #include <drm/drmP.h>
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
@@ -104,9 +105,11 @@
 {
 	bool has_aliasing_ppgtt;
 	bool has_full_ppgtt;
+	bool has_full_48bit_ppgtt;
 
 	has_aliasing_ppgtt = INTEL_INFO(dev)->gen >= 6;
 	has_full_ppgtt = INTEL_INFO(dev)->gen >= 7;
+	has_full_48bit_ppgtt = IS_BROADWELL(dev) || INTEL_INFO(dev)->gen >= 9;
 
 	if (intel_vgpu_active(dev))
 		has_full_ppgtt = false; /* emulation is too hard */
@@ -125,6 +128,9 @@
 	if (enable_ppgtt == 2 && has_full_ppgtt)
 		return 2;
 
+	if (enable_ppgtt == 3 && has_full_48bit_ppgtt)
+		return 3;
+
 #ifdef CONFIG_INTEL_IOMMU
 	/* Disable ppgtt on SNB if VT-d is on. */
 	if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) {
@@ -141,7 +147,7 @@
 	}
 
 	if (INTEL_INFO(dev)->gen >= 8 && i915.enable_execlists)
-		return 2;
+		return has_full_48bit_ppgtt ? 3 : 2;
 	else
 		return has_aliasing_ppgtt ? 1 : 0;
 }
@@ -661,10 +667,10 @@
 		return ret;
 
 	intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
-	intel_ring_emit(ring, GEN8_RING_PDP_UDW(ring, entry));
+	intel_ring_emit_reg(ring, GEN8_RING_PDP_UDW(ring, entry));
 	intel_ring_emit(ring, upper_32_bits(addr));
 	intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
-	intel_ring_emit(ring, GEN8_RING_PDP_LDW(ring, entry));
+	intel_ring_emit_reg(ring, GEN8_RING_PDP_LDW(ring, entry));
 	intel_ring_emit(ring, lower_32_bits(addr));
 	intel_ring_advance(ring);
 
@@ -904,14 +910,13 @@
 	enum vgt_g2v_type msg;
 	struct drm_device *dev = ppgtt->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	unsigned int offset = vgtif_reg(pdp0_lo);
 	int i;
 
 	if (USES_FULL_48BIT_PPGTT(dev)) {
 		u64 daddr = px_dma(&ppgtt->pml4);
 
-		I915_WRITE(offset, lower_32_bits(daddr));
-		I915_WRITE(offset + 4, upper_32_bits(daddr));
+		I915_WRITE(vgtif_reg(pdp[0].lo), lower_32_bits(daddr));
+		I915_WRITE(vgtif_reg(pdp[0].hi), upper_32_bits(daddr));
 
 		msg = (create ? VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE :
 				VGT_G2V_PPGTT_L4_PAGE_TABLE_DESTROY);
@@ -919,10 +924,8 @@
 		for (i = 0; i < GEN8_LEGACY_PDPES; i++) {
 			u64 daddr = i915_page_dir_dma_addr(ppgtt, i);
 
-			I915_WRITE(offset, lower_32_bits(daddr));
-			I915_WRITE(offset + 4, upper_32_bits(daddr));
-
-			offset += 8;
+			I915_WRITE(vgtif_reg(pdp[i].lo), lower_32_bits(daddr));
+			I915_WRITE(vgtif_reg(pdp[i].hi), upper_32_bits(daddr));
 		}
 
 		msg = (create ? VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE :
@@ -1662,9 +1665,9 @@
 		return ret;
 
 	intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(2));
-	intel_ring_emit(ring, RING_PP_DIR_DCLV(ring));
+	intel_ring_emit_reg(ring, RING_PP_DIR_DCLV(ring));
 	intel_ring_emit(ring, PP_DIR_DCLV_2G);
-	intel_ring_emit(ring, RING_PP_DIR_BASE(ring));
+	intel_ring_emit_reg(ring, RING_PP_DIR_BASE(ring));
 	intel_ring_emit(ring, get_pd_offset(ppgtt));
 	intel_ring_emit(ring, MI_NOOP);
 	intel_ring_advance(ring);
@@ -1699,9 +1702,9 @@
 		return ret;
 
 	intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(2));
-	intel_ring_emit(ring, RING_PP_DIR_DCLV(ring));
+	intel_ring_emit_reg(ring, RING_PP_DIR_DCLV(ring));
 	intel_ring_emit(ring, PP_DIR_DCLV_2G);
-	intel_ring_emit(ring, RING_PP_DIR_BASE(ring));
+	intel_ring_emit_reg(ring, RING_PP_DIR_BASE(ring));
 	intel_ring_emit(ring, get_pd_offset(ppgtt));
 	intel_ring_emit(ring, MI_NOOP);
 	intel_ring_advance(ring);
@@ -2528,6 +2531,26 @@
 	return 0;
 }
 
+struct ggtt_bind_vma__cb {
+	struct i915_vma *vma;
+	enum i915_cache_level cache_level;
+	u32 flags;
+};
+
+static int ggtt_bind_vma__cb(void *_arg)
+{
+	struct ggtt_bind_vma__cb *arg = _arg;
+	return ggtt_bind_vma(arg->vma, arg->cache_level, arg->flags);
+}
+
+static int ggtt_bind_vma__BKL(struct i915_vma *vma,
+			      enum i915_cache_level cache_level,
+			      u32 flags)
+{
+	struct ggtt_bind_vma__cb arg = { vma, cache_level, flags };
+	return stop_machine(ggtt_bind_vma__cb, &arg, NULL);
+}
+
 static int aliasing_gtt_bind_vma(struct i915_vma *vma,
 				 enum i915_cache_level cache_level,
 				 u32 flags)
@@ -2996,6 +3019,9 @@
 	dev_priv->gtt.base.bind_vma = ggtt_bind_vma;
 	dev_priv->gtt.base.unbind_vma = ggtt_unbind_vma;
 
+	if (IS_CHERRYVIEW(dev))
+		dev_priv->gtt.base.bind_vma = ggtt_bind_vma__BKL;
+
 	return ret;
 }
 
@@ -3303,7 +3329,7 @@
 intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view,
 			  struct drm_i915_gem_object *obj)
 {
-	struct intel_rotation_info *rot_info = &ggtt_view->rotation_info;
+	struct intel_rotation_info *rot_info = &ggtt_view->params.rotation_info;
 	unsigned int size_pages = rot_info->size >> PAGE_SHIFT;
 	unsigned int size_pages_uv;
 	struct sg_page_iter sg_iter;
@@ -3535,7 +3561,7 @@
 	if (view->type == I915_GGTT_VIEW_NORMAL) {
 		return obj->base.size;
 	} else if (view->type == I915_GGTT_VIEW_ROTATED) {
-		return view->rotation_info.size;
+		return view->params.rotation_info.size;
 	} else if (view->type == I915_GGTT_VIEW_PARTIAL) {
 		return view->params.partial.size << PAGE_SHIFT;
 	} else {
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
index a216397..877c32c 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.h
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
@@ -156,13 +156,10 @@
 			u64 offset;
 			unsigned int size;
 		} partial;
+		struct intel_rotation_info rotation_info;
 	} params;
 
 	struct sg_table *pages;
-
-	union {
-		struct intel_rotation_info rotation_info;
-	};
 };
 
 extern const struct i915_ggtt_view i915_ggtt_view_normal;
@@ -556,7 +553,7 @@
 
 	if (a->type != b->type)
 		return false;
-	if (a->type == I915_GGTT_VIEW_PARTIAL)
+	if (a->type != I915_GGTT_VIEW_NORMAL)
 		return !memcmp(&a->params, &b->params, sizeof(a->params));
 	return true;
 }
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index 87e919a..3476877 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -433,7 +433,8 @@
 					 &reserved_size);
 		break;
 	default:
-		if (IS_BROADWELL(dev_priv) || IS_SKYLAKE(dev_priv))
+		if (IS_BROADWELL(dev_priv) ||
+		    IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev))
 			bdw_get_stolen_reserved(dev_priv, &reserved_base,
 						&reserved_size);
 		else
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 8a6717c..7410f6c 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -176,6 +176,8 @@
 		return -EINVAL;
 	}
 
+	intel_runtime_pm_get(dev_priv);
+
 	mutex_lock(&dev->struct_mutex);
 	if (obj->pin_display || obj->framebuffer_references) {
 		ret = -EBUSY;
@@ -269,6 +271,8 @@
 	drm_gem_object_unreference(&obj->base);
 	mutex_unlock(&dev->struct_mutex);
 
+	intel_runtime_pm_put(dev_priv);
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index 2f04e4f..06ca408 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -366,6 +366,17 @@
 	err_printf(m, "Suspend count: %u\n", error->suspend_count);
 	err_printf(m, "PCI ID: 0x%04x\n", dev->pdev->device);
 	err_printf(m, "IOMMU enabled?: %d\n", error->iommu);
+
+	if (HAS_CSR(dev)) {
+		struct intel_csr *csr = &dev_priv->csr;
+
+		err_printf(m, "DMC loaded: %s\n",
+			   yesno(csr->dmc_payload != NULL));
+		err_printf(m, "DMC fw version: %d.%d\n",
+			   CSR_VERSION_MAJOR(csr->version),
+			   CSR_VERSION_MINOR(csr->version));
+	}
+
 	err_printf(m, "EIR: 0x%08x\n", error->eir);
 	err_printf(m, "IER: 0x%08x\n", error->ier);
 	if (INTEL_INFO(dev)->gen >= 8) {
@@ -862,7 +873,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	if (INTEL_INFO(dev)->gen >= 6) {
-		ering->rc_psmi = I915_READ(ring->mmio_base + 0x50);
+		ering->rc_psmi = I915_READ(RING_PSMI_CTL(ring->mmio_base));
 		ering->fault_reg = I915_READ(RING_FAULT_REG(ring));
 		if (INTEL_INFO(dev)->gen >= 8)
 			gen8_record_semaphore_state(dev_priv, error, ring, ering);
@@ -899,7 +910,7 @@
 	ering->ctl = I915_READ_CTL(ring);
 
 	if (I915_NEED_GFX_HWS(dev)) {
-		int mmio;
+		i915_reg_t mmio;
 
 		if (IS_GEN7(dev)) {
 			switch (ring->id) {
@@ -1071,6 +1082,25 @@
 		list_for_each_entry(request, &ring->request_list, list) {
 			struct drm_i915_error_request *erq;
 
+			if (count >= error->ring[i].num_requests) {
+				/*
+				 * If the ring request list was changed in
+				 * between the point where the error request
+				 * list was created and dimensioned and this
+				 * point then just exit early to avoid crashes.
+				 *
+				 * We don't need to communicate that the
+				 * request list changed state during error
+				 * state capture and that the error state is
+				 * slightly incorrect as a consequence since we
+				 * are typically only interested in the request
+				 * list state at the point of error state
+				 * capture, not in any changes happening during
+				 * the capture.
+				 */
+				break;
+			}
+
 			erq = &error->ring[i].requests[count++];
 			erq->seqno = request->seqno;
 			erq->jiffies = request->emitted_jiffies;
@@ -1181,7 +1211,7 @@
 	if (IS_VALLEYVIEW(dev)) {
 		error->gtier[0] = I915_READ(GTIER);
 		error->ier = I915_READ(VLV_IER);
-		error->forcewake = I915_READ(FORCEWAKE_VLV);
+		error->forcewake = I915_READ_FW(FORCEWAKE_VLV);
 	}
 
 	if (IS_GEN7(dev))
@@ -1193,14 +1223,14 @@
 	}
 
 	if (IS_GEN6(dev)) {
-		error->forcewake = I915_READ(FORCEWAKE);
+		error->forcewake = I915_READ_FW(FORCEWAKE);
 		error->gab_ctl = I915_READ(GAB_CTL);
 		error->gfx_mode = I915_READ(GFX_MODE);
 	}
 
 	/* 2: Registers which belong to multiple generations */
 	if (INTEL_INFO(dev)->gen >= 7)
-		error->forcewake = I915_READ(FORCEWAKE_MT);
+		error->forcewake = I915_READ_FW(FORCEWAKE_MT);
 
 	if (INTEL_INFO(dev)->gen >= 6) {
 		error->derrmr = I915_READ(DERRMR);
diff --git a/drivers/gpu/drm/i915/i915_guc_reg.h b/drivers/gpu/drm/i915/i915_guc_reg.h
index c4cb1c0..685c799 100644
--- a/drivers/gpu/drm/i915/i915_guc_reg.h
+++ b/drivers/gpu/drm/i915/i915_guc_reg.h
@@ -26,7 +26,7 @@
 
 /* Definitions of GuC H/W registers, bits, etc */
 
-#define GUC_STATUS			0xc000
+#define GUC_STATUS			_MMIO(0xc000)
 #define   GS_BOOTROM_SHIFT		1
 #define   GS_BOOTROM_MASK		  (0x7F << GS_BOOTROM_SHIFT)
 #define   GS_BOOTROM_RSA_FAILED		  (0x50 << GS_BOOTROM_SHIFT)
@@ -39,40 +39,41 @@
 #define   GS_MIA_MASK			  (0x07 << GS_MIA_SHIFT)
 #define   GS_MIA_CORE_STATE		  (1 << GS_MIA_SHIFT)
 
-#define SOFT_SCRATCH(n)			(0xc180 + ((n) * 4))
+#define SOFT_SCRATCH(n)			_MMIO(0xc180 + (n) * 4)
 
-#define UOS_RSA_SCRATCH(i)		(0xc200 + (i) * 4)
-#define DMA_ADDR_0_LOW			0xc300
-#define DMA_ADDR_0_HIGH			0xc304
-#define DMA_ADDR_1_LOW			0xc308
-#define DMA_ADDR_1_HIGH			0xc30c
+#define UOS_RSA_SCRATCH(i)		_MMIO(0xc200 + (i) * 4)
+#define   UOS_RSA_SCRATCH_MAX_COUNT	  64
+#define DMA_ADDR_0_LOW			_MMIO(0xc300)
+#define DMA_ADDR_0_HIGH			_MMIO(0xc304)
+#define DMA_ADDR_1_LOW			_MMIO(0xc308)
+#define DMA_ADDR_1_HIGH			_MMIO(0xc30c)
 #define   DMA_ADDRESS_SPACE_WOPCM	  (7 << 16)
 #define   DMA_ADDRESS_SPACE_GTT		  (8 << 16)
-#define DMA_COPY_SIZE			0xc310
-#define DMA_CTRL			0xc314
+#define DMA_COPY_SIZE			_MMIO(0xc310)
+#define DMA_CTRL			_MMIO(0xc314)
 #define   UOS_MOVE			  (1<<4)
 #define   START_DMA			  (1<<0)
-#define DMA_GUC_WOPCM_OFFSET		0xc340
+#define DMA_GUC_WOPCM_OFFSET		_MMIO(0xc340)
 #define   GUC_WOPCM_OFFSET_VALUE	  0x80000	/* 512KB */
-#define GUC_MAX_IDLE_COUNT		0xC3E4
+#define GUC_MAX_IDLE_COUNT		_MMIO(0xC3E4)
 
-#define GUC_WOPCM_SIZE			0xc050
+#define GUC_WOPCM_SIZE			_MMIO(0xc050)
 #define   GUC_WOPCM_SIZE_VALUE  	  (0x80 << 12)	/* 512KB */
 
 /* GuC addresses below GUC_WOPCM_TOP don't map through the GTT */
 #define	GUC_WOPCM_TOP			(GUC_WOPCM_SIZE_VALUE)
 
-#define GEN8_GT_PM_CONFIG		0x138140
-#define GEN9LP_GT_PM_CONFIG		0x138140
-#define GEN9_GT_PM_CONFIG		0x13816c
+#define GEN8_GT_PM_CONFIG		_MMIO(0x138140)
+#define GEN9LP_GT_PM_CONFIG		_MMIO(0x138140)
+#define GEN9_GT_PM_CONFIG		_MMIO(0x13816c)
 #define   GT_DOORBELL_ENABLE		  (1<<0)
 
-#define GEN8_GTCR			0x4274
+#define GEN8_GTCR			_MMIO(0x4274)
 #define   GEN8_GTCR_INVALIDATE		  (1<<0)
 
-#define GUC_ARAT_C6DIS			0xA178
+#define GUC_ARAT_C6DIS			_MMIO(0xA178)
 
-#define GUC_SHIM_CONTROL		0xc064
+#define GUC_SHIM_CONTROL		_MMIO(0xc064)
 #define   GUC_DISABLE_SRAM_INIT_TO_ZEROES	(1<<0)
 #define   GUC_ENABLE_READ_CACHE_LOGIC		(1<<1)
 #define   GUC_ENABLE_MIA_CACHING		(1<<2)
@@ -89,21 +90,21 @@
 				 GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA	| \
 				 GUC_ENABLE_MIA_CLOCK_GATING)
 
-#define HOST2GUC_INTERRUPT		0xc4c8
+#define HOST2GUC_INTERRUPT		_MMIO(0xc4c8)
 #define   HOST2GUC_TRIGGER		  (1<<0)
 
 #define DRBMISC1			0x1984
 #define   DOORBELL_ENABLE		  (1<<0)
 
-#define GEN8_DRBREGL(x)			(0x1000 + (x) * 8)
+#define GEN8_DRBREGL(x)			_MMIO(0x1000 + (x) * 8)
 #define   GEN8_DRB_VALID		  (1<<0)
-#define GEN8_DRBREGU(x)			(GEN8_DRBREGL(x) + 4)
+#define GEN8_DRBREGU(x)			_MMIO(0x1000 + (x) * 8 + 4)
 
-#define DE_GUCRMR			0x44054
+#define DE_GUCRMR			_MMIO(0x44054)
 
-#define GUC_BCS_RCS_IER			0xC550
-#define GUC_VCS2_VCS1_IER		0xC554
-#define GUC_WD_VECS_IER			0xC558
-#define GUC_PM_P24C_IER			0xC55C
+#define GUC_BCS_RCS_IER			_MMIO(0xC550)
+#define GUC_VCS2_VCS1_IER		_MMIO(0xC554)
+#define GUC_WD_VECS_IER			_MMIO(0xC558)
+#define GUC_PM_P24C_IER			_MMIO(0xC55C)
 
 #endif
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 036b42b..ed9f100 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -27,7 +27,7 @@
 #include "intel_guc.h"
 
 /**
- * DOC: GuC Client
+ * DOC: GuC-based command submission
  *
  * i915_guc_client:
  * We use the term client to avoid confusion with contexts. A i915_guc_client is
@@ -161,9 +161,9 @@
 	data[0] = HOST2GUC_ACTION_SAMPLE_FORCEWAKE;
 	/* WaRsDisableCoarsePowerGating:skl,bxt */
 	if (!intel_enable_rc6(dev_priv->dev) ||
-	    (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) ||
-	    (IS_SKL_GT3(dev) && (INTEL_REVID(dev) <= SKL_REVID_E0)) ||
-	    (IS_SKL_GT4(dev) && (INTEL_REVID(dev) <= SKL_REVID_E0)))
+	    IS_BXT_REVID(dev, 0, BXT_REVID_A1) ||
+	    (IS_SKL_GT3(dev) && IS_SKL_REVID(dev, 0, SKL_REVID_E0)) ||
+	    (IS_SKL_GT4(dev) && IS_SKL_REVID(dev, 0, SKL_REVID_E0)))
 		data[1] = 0;
 	else
 		/* bit 0 and 1 are for Render and Media domain separately */
@@ -258,7 +258,7 @@
 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
 	struct guc_doorbell_info *doorbell;
 	void *base;
-	int drbreg = GEN8_DRBREGL(client->doorbell_id);
+	i915_reg_t drbreg = GEN8_DRBREGL(client->doorbell_id);
 	int value;
 
 	base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0));
@@ -588,8 +588,7 @@
 /**
  * i915_guc_submit() - Submit commands through GuC
  * @client:	the guc client where commands will go through
- * @ctx:	LRC where commands come from
- * @ring:	HW engine that will excute the commands
+ * @rq:		request associated with the commands
  *
  * Return:	0 if succeed
  */
@@ -731,7 +730,8 @@
  * 		The kernel client to replace ExecList submission is created with
  * 		NORMAL priority. Priority of a client for scheduler can be HIGH,
  * 		while a preemption context can use CRITICAL.
- * @ctx		the context to own the client (we use the default render context)
+ * @ctx:	the context that owns the client (we use the default render
+ * 		context)
  *
  * Return:	An i915_guc_client object if success.
  */
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 0d228f9..c8ba949 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -139,7 +139,8 @@
 /*
  * We should clear IMR at preinstall/uninstall, and just check at postinstall.
  */
-static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv, u32 reg)
+static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv,
+				    i915_reg_t reg)
 {
 	u32 val = I915_READ(reg);
 
@@ -147,7 +148,7 @@
 		return;
 
 	WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n",
-	     reg, val);
+	     i915_mmio_reg_offset(reg), val);
 	I915_WRITE(reg, 0xffffffff);
 	POSTING_READ(reg);
 	I915_WRITE(reg, 0xffffffff);
@@ -283,17 +284,17 @@
 	ilk_update_gt_irq(dev_priv, mask, 0);
 }
 
-static u32 gen6_pm_iir(struct drm_i915_private *dev_priv)
+static i915_reg_t gen6_pm_iir(struct drm_i915_private *dev_priv)
 {
 	return INTEL_INFO(dev_priv)->gen >= 8 ? GEN8_GT_IIR(2) : GEN6_PMIIR;
 }
 
-static u32 gen6_pm_imr(struct drm_i915_private *dev_priv)
+static i915_reg_t gen6_pm_imr(struct drm_i915_private *dev_priv)
 {
 	return INTEL_INFO(dev_priv)->gen >= 8 ? GEN8_GT_IMR(2) : GEN6_PMIMR;
 }
 
-static u32 gen6_pm_ier(struct drm_i915_private *dev_priv)
+static i915_reg_t gen6_pm_ier(struct drm_i915_private *dev_priv)
 {
 	return INTEL_INFO(dev_priv)->gen >= 8 ? GEN8_GT_IER(2) : GEN6_PMIER;
 }
@@ -350,7 +351,7 @@
 void gen6_reset_rps_interrupts(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	uint32_t reg = gen6_pm_iir(dev_priv);
+	i915_reg_t reg = gen6_pm_iir(dev_priv);
 
 	spin_lock_irq(&dev_priv->irq_lock);
 	I915_WRITE(reg, dev_priv->pm_rps_events);
@@ -477,7 +478,7 @@
 __i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
 		       u32 enable_mask, u32 status_mask)
 {
-	u32 reg = PIPESTAT(pipe);
+	i915_reg_t reg = PIPESTAT(pipe);
 	u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
 
 	assert_spin_locked(&dev_priv->irq_lock);
@@ -504,7 +505,7 @@
 __i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
 		        u32 enable_mask, u32 status_mask)
 {
-	u32 reg = PIPESTAT(pipe);
+	i915_reg_t reg = PIPESTAT(pipe);
 	u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
 
 	assert_spin_locked(&dev_priv->irq_lock);
@@ -665,8 +666,7 @@
 static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	unsigned long high_frame;
-	unsigned long low_frame;
+	i915_reg_t high_frame, low_frame;
 	u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
 	struct intel_crtc *intel_crtc =
 		to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
@@ -717,9 +717,7 @@
 	return I915_READ(PIPE_FRMCOUNT_G4X(pipe));
 }
 
-/* raw reads, only for fast reads of display block, no need for forcewake etc. */
-#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
-
+/* I915_READ_FW, only for fast reads of display block, no need for forcewake etc. */
 static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
 {
 	struct drm_device *dev = crtc->base.dev;
@@ -733,9 +731,9 @@
 		vtotal /= 2;
 
 	if (IS_GEN2(dev))
-		position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
+		position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
 	else
-		position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
+		position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
 
 	/*
 	 * On HSW, the DSL reg (0x70000) appears to return 0 if we
@@ -827,7 +825,7 @@
 		 * We can split this into vertical and horizontal
 		 * scanout position.
 		 */
-		position = (__raw_i915_read32(dev_priv, PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
+		position = (I915_READ_FW(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
 
 		/* convert to pixel counts */
 		vbl_start *= htotal;
@@ -1188,7 +1186,7 @@
 	POSTING_READ(GEN7_MISCCPCTL);
 
 	while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) {
-		u32 reg;
+		i915_reg_t reg;
 
 		slice--;
 		if (WARN_ON_ONCE(slice >= NUM_L3_SLICES(dev_priv->dev)))
@@ -1196,7 +1194,7 @@
 
 		dev_priv->l3_parity.which_slice &= ~(1<<slice);
 
-		reg = GEN7_L3CDERRST1 + (slice * 0x200);
+		reg = GEN7_L3CDERRST1(slice);
 
 		error_status = I915_READ(reg);
 		row = GEN7_PARITY_ERROR_ROW(error_status);
@@ -1290,70 +1288,69 @@
 		ivybridge_parity_error_irq_handler(dev, gt_iir);
 }
 
+static __always_inline void
+gen8_cs_irq_handler(struct intel_engine_cs *ring, u32 iir, int test_shift)
+{
+	if (iir & (GT_RENDER_USER_INTERRUPT << test_shift))
+		notify_ring(ring);
+	if (iir & (GT_CONTEXT_SWITCH_INTERRUPT << test_shift))
+		intel_lrc_irq_handler(ring);
+}
+
 static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
 				       u32 master_ctl)
 {
 	irqreturn_t ret = IRQ_NONE;
 
 	if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) {
-		u32 tmp = I915_READ_FW(GEN8_GT_IIR(0));
-		if (tmp) {
-			I915_WRITE_FW(GEN8_GT_IIR(0), tmp);
+		u32 iir = I915_READ_FW(GEN8_GT_IIR(0));
+		if (iir) {
+			I915_WRITE_FW(GEN8_GT_IIR(0), iir);
 			ret = IRQ_HANDLED;
 
-			if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT))
-				intel_lrc_irq_handler(&dev_priv->ring[RCS]);
-			if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT))
-				notify_ring(&dev_priv->ring[RCS]);
+			gen8_cs_irq_handler(&dev_priv->ring[RCS],
+					iir, GEN8_RCS_IRQ_SHIFT);
 
-			if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT))
-				intel_lrc_irq_handler(&dev_priv->ring[BCS]);
-			if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT))
-				notify_ring(&dev_priv->ring[BCS]);
+			gen8_cs_irq_handler(&dev_priv->ring[BCS],
+					iir, GEN8_BCS_IRQ_SHIFT);
 		} else
 			DRM_ERROR("The master control interrupt lied (GT0)!\n");
 	}
 
 	if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) {
-		u32 tmp = I915_READ_FW(GEN8_GT_IIR(1));
-		if (tmp) {
-			I915_WRITE_FW(GEN8_GT_IIR(1), tmp);
+		u32 iir = I915_READ_FW(GEN8_GT_IIR(1));
+		if (iir) {
+			I915_WRITE_FW(GEN8_GT_IIR(1), iir);
 			ret = IRQ_HANDLED;
 
-			if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT))
-				intel_lrc_irq_handler(&dev_priv->ring[VCS]);
-			if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT))
-				notify_ring(&dev_priv->ring[VCS]);
+			gen8_cs_irq_handler(&dev_priv->ring[VCS],
+					iir, GEN8_VCS1_IRQ_SHIFT);
 
-			if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT))
-				intel_lrc_irq_handler(&dev_priv->ring[VCS2]);
-			if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT))
-				notify_ring(&dev_priv->ring[VCS2]);
+			gen8_cs_irq_handler(&dev_priv->ring[VCS2],
+					iir, GEN8_VCS2_IRQ_SHIFT);
 		} else
 			DRM_ERROR("The master control interrupt lied (GT1)!\n");
 	}
 
 	if (master_ctl & GEN8_GT_VECS_IRQ) {
-		u32 tmp = I915_READ_FW(GEN8_GT_IIR(3));
-		if (tmp) {
-			I915_WRITE_FW(GEN8_GT_IIR(3), tmp);
+		u32 iir = I915_READ_FW(GEN8_GT_IIR(3));
+		if (iir) {
+			I915_WRITE_FW(GEN8_GT_IIR(3), iir);
 			ret = IRQ_HANDLED;
 
-			if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT))
-				intel_lrc_irq_handler(&dev_priv->ring[VECS]);
-			if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT))
-				notify_ring(&dev_priv->ring[VECS]);
+			gen8_cs_irq_handler(&dev_priv->ring[VECS],
+					iir, GEN8_VECS_IRQ_SHIFT);
 		} else
 			DRM_ERROR("The master control interrupt lied (GT3)!\n");
 	}
 
 	if (master_ctl & GEN8_GT_PM_IRQ) {
-		u32 tmp = I915_READ_FW(GEN8_GT_IIR(2));
-		if (tmp & dev_priv->pm_rps_events) {
+		u32 iir = I915_READ_FW(GEN8_GT_IIR(2));
+		if (iir & dev_priv->pm_rps_events) {
 			I915_WRITE_FW(GEN8_GT_IIR(2),
-				      tmp & dev_priv->pm_rps_events);
+				      iir & dev_priv->pm_rps_events);
 			ret = IRQ_HANDLED;
-			gen6_rps_irq_handler(dev_priv, tmp);
+			gen6_rps_irq_handler(dev_priv, iir);
 		} else
 			DRM_ERROR("The master control interrupt lied (PM)!\n");
 	}
@@ -1625,7 +1622,7 @@
 
 	spin_lock(&dev_priv->irq_lock);
 	for_each_pipe(dev_priv, pipe) {
-		int reg;
+		i915_reg_t reg;
 		u32 mask, iir_bit = 0;
 
 		/*
@@ -2354,9 +2351,13 @@
 				spt_irq_handler(dev, pch_iir);
 			else
 				cpt_irq_handler(dev, pch_iir);
-		} else
-			DRM_ERROR("The master control interrupt lied (SDE)!\n");
-
+		} else {
+			/*
+			 * Like on previous PCH there seems to be something
+			 * fishy going on with forwarding PCH interrupts.
+			 */
+			DRM_DEBUG_DRIVER("The master control interrupt lied (SDE)!\n");
+		}
 	}
 
 	I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
@@ -3869,7 +3870,7 @@
 			DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
 
 		for_each_pipe(dev_priv, pipe) {
-			int reg = PIPESTAT(pipe);
+			i915_reg_t reg = PIPESTAT(pipe);
 			pipe_stats[pipe] = I915_READ(reg);
 
 			/*
@@ -4050,7 +4051,7 @@
 			DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
 
 		for_each_pipe(dev_priv, pipe) {
-			int reg = PIPESTAT(pipe);
+			i915_reg_t reg = PIPESTAT(pipe);
 			pipe_stats[pipe] = I915_READ(reg);
 
 			/* Clear the PIPE*STAT regs before the IIR */
@@ -4272,7 +4273,7 @@
 			DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
 
 		for_each_pipe(dev_priv, pipe) {
-			int reg = PIPESTAT(pipe);
+			i915_reg_t reg = PIPESTAT(pipe);
 			pipe_stats[pipe] = I915_READ(reg);
 
 			/*
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index 4be13a5..835d609 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -32,6 +32,7 @@
 	.panel_use_ssc = -1,
 	.vbt_sdvo_panel_type = -1,
 	.enable_rc6 = -1,
+	.enable_dc = -1,
 	.enable_fbc = -1,
 	.enable_execlists = -1,
 	.enable_hangcheck = true,
@@ -80,6 +81,11 @@
 	"For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. "
 	"default: -1 (use per-chip default)");
 
+module_param_named_unsafe(enable_dc, i915.enable_dc, int, 0400);
+MODULE_PARM_DESC(enable_dc,
+	"Enable power-saving display C-states. "
+	"(-1=auto [default]; 0=disable; 1=up to DC5; 2=up to DC6)");
+
 module_param_named_unsafe(enable_fbc, i915.enable_fbc, int, 0600);
 MODULE_PARM_DESC(enable_fbc,
 	"Enable frame buffer compression for power savings "
@@ -112,7 +118,7 @@
 module_param_named_unsafe(enable_ppgtt, i915.enable_ppgtt, int, 0400);
 MODULE_PARM_DESC(enable_ppgtt,
 	"Override PPGTT usage. "
-	"(-1=auto [default], 0=disabled, 1=aliasing, 2=full)");
+	"(-1=auto [default], 0=disabled, 1=aliasing, 2=full, 3=full with extended address space)");
 
 module_param_named_unsafe(enable_execlists, i915.enable_execlists, int, 0400);
 MODULE_PARM_DESC(enable_execlists,
@@ -126,7 +132,7 @@
 MODULE_PARM_DESC(preliminary_hw_support,
 	"Enable preliminary hardware support.");
 
-module_param_named_unsafe(disable_power_well, i915.disable_power_well, int, 0600);
+module_param_named_unsafe(disable_power_well, i915.disable_power_well, int, 0400);
 MODULE_PARM_DESC(disable_power_well,
 	"Disable display power wells when possible "
 	"(-1=auto [default], 0=power wells always on, 1=power wells disabled when possible)");
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index bc7b8fa..1a12d44 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -25,14 +25,43 @@
 #ifndef _I915_REG_H_
 #define _I915_REG_H_
 
+typedef struct {
+	uint32_t reg;
+} i915_reg_t;
+
+#define _MMIO(r) ((const i915_reg_t){ .reg = (r) })
+
+#define INVALID_MMIO_REG _MMIO(0)
+
+static inline uint32_t i915_mmio_reg_offset(i915_reg_t reg)
+{
+	return reg.reg;
+}
+
+static inline bool i915_mmio_reg_equal(i915_reg_t a, i915_reg_t b)
+{
+	return i915_mmio_reg_offset(a) == i915_mmio_reg_offset(b);
+}
+
+static inline bool i915_mmio_reg_valid(i915_reg_t reg)
+{
+	return !i915_mmio_reg_equal(reg, INVALID_MMIO_REG);
+}
+
 #define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a)))
+#define _MMIO_PIPE(pipe, a, b) _MMIO(_PIPE(pipe, a, b))
 #define _PLANE(plane, a, b) _PIPE(plane, a, b)
-#define _TRANSCODER(tran, a, b) ((a) + (tran)*((b)-(a)))
+#define _MMIO_PLANE(plane, a, b) _MMIO_PIPE(plane, a, b)
+#define _TRANS(tran, a, b) ((a) + (tran)*((b)-(a)))
+#define _MMIO_TRANS(tran, a, b) _MMIO(_TRANS(tran, a, b))
 #define _PORT(port, a, b) ((a) + (port)*((b)-(a)))
+#define _MMIO_PORT(port, a, b) _MMIO(_PORT(port, a, b))
 #define _PIPE3(pipe, a, b, c) ((pipe) == PIPE_A ? (a) : \
 			       (pipe) == PIPE_B ? (b) : (c))
+#define _MMIO_PIPE3(pipe, a, b, c) _MMIO(_PIPE3(pipe, a, b, c))
 #define _PORT3(port, a, b, c) ((port) == PORT_A ? (a) : \
 			       (port) == PORT_B ? (b) : (c))
+#define _MMIO_PORT3(pipe, a, b, c) _MMIO(_PORT3(pipe, a, b, c))
 
 #define _MASKED_FIELD(mask, value) ({					   \
 	if (__builtin_constant_p(mask))					   \
@@ -105,14 +134,14 @@
 #define  GRDOM_RESET_STATUS (1<<1)
 #define  GRDOM_RESET_ENABLE (1<<0)
 
-#define ILK_GDSR (MCHBAR_MIRROR_BASE + 0x2ca4)
+#define ILK_GDSR _MMIO(MCHBAR_MIRROR_BASE + 0x2ca4)
 #define  ILK_GRDOM_FULL		(0<<1)
 #define  ILK_GRDOM_RENDER	(1<<1)
 #define  ILK_GRDOM_MEDIA	(3<<1)
 #define  ILK_GRDOM_MASK		(3<<1)
 #define  ILK_GRDOM_RESET_ENABLE (1<<0)
 
-#define GEN6_MBCUNIT_SNPCR	0x900c /* for LLC config */
+#define GEN6_MBCUNIT_SNPCR	_MMIO(0x900c) /* for LLC config */
 #define   GEN6_MBC_SNPCR_SHIFT	21
 #define   GEN6_MBC_SNPCR_MASK	(3<<21)
 #define   GEN6_MBC_SNPCR_MAX	(0<<21)
@@ -120,31 +149,31 @@
 #define   GEN6_MBC_SNPCR_LOW	(2<<21)
 #define   GEN6_MBC_SNPCR_MIN	(3<<21) /* only 1/16th of the cache is shared */
 
-#define VLV_G3DCTL		0x9024
-#define VLV_GSCKGCTL		0x9028
+#define VLV_G3DCTL		_MMIO(0x9024)
+#define VLV_GSCKGCTL		_MMIO(0x9028)
 
-#define GEN6_MBCTL		0x0907c
+#define GEN6_MBCTL		_MMIO(0x0907c)
 #define   GEN6_MBCTL_ENABLE_BOOT_FETCH	(1 << 4)
 #define   GEN6_MBCTL_CTX_FETCH_NEEDED	(1 << 3)
 #define   GEN6_MBCTL_BME_UPDATE_ENABLE	(1 << 2)
 #define   GEN6_MBCTL_MAE_UPDATE_ENABLE	(1 << 1)
 #define   GEN6_MBCTL_BOOT_FETCH_MECH	(1 << 0)
 
-#define GEN6_GDRST	0x941c
+#define GEN6_GDRST	_MMIO(0x941c)
 #define  GEN6_GRDOM_FULL		(1 << 0)
 #define  GEN6_GRDOM_RENDER		(1 << 1)
 #define  GEN6_GRDOM_MEDIA		(1 << 2)
 #define  GEN6_GRDOM_BLT			(1 << 3)
 
-#define RING_PP_DIR_BASE(ring)		((ring)->mmio_base+0x228)
-#define RING_PP_DIR_BASE_READ(ring)	((ring)->mmio_base+0x518)
-#define RING_PP_DIR_DCLV(ring)		((ring)->mmio_base+0x220)
+#define RING_PP_DIR_BASE(ring)		_MMIO((ring)->mmio_base+0x228)
+#define RING_PP_DIR_BASE_READ(ring)	_MMIO((ring)->mmio_base+0x518)
+#define RING_PP_DIR_DCLV(ring)		_MMIO((ring)->mmio_base+0x220)
 #define   PP_DIR_DCLV_2G		0xffffffff
 
-#define GEN8_RING_PDP_UDW(ring, n)	((ring)->mmio_base+0x270 + ((n) * 8 + 4))
-#define GEN8_RING_PDP_LDW(ring, n)	((ring)->mmio_base+0x270 + (n) * 8)
+#define GEN8_RING_PDP_UDW(ring, n)	_MMIO((ring)->mmio_base+0x270 + (n) * 8 + 4)
+#define GEN8_RING_PDP_LDW(ring, n)	_MMIO((ring)->mmio_base+0x270 + (n) * 8)
 
-#define GEN8_R_PWR_CLK_STATE		0x20C8
+#define GEN8_R_PWR_CLK_STATE		_MMIO(0x20C8)
 #define   GEN8_RPCS_ENABLE		(1 << 31)
 #define   GEN8_RPCS_S_CNT_ENABLE	(1 << 18)
 #define   GEN8_RPCS_S_CNT_SHIFT		15
@@ -157,7 +186,7 @@
 #define   GEN8_RPCS_EU_MIN_SHIFT	0
 #define   GEN8_RPCS_EU_MIN_MASK		(0xf << GEN8_RPCS_EU_MIN_SHIFT)
 
-#define GAM_ECOCHK			0x4090
+#define GAM_ECOCHK			_MMIO(0x4090)
 #define   BDW_DISABLE_HDC_INVALIDATION	(1<<25)
 #define   ECOCHK_SNB_BIT		(1<<10)
 #define   ECOCHK_DIS_TLB		(1<<8)
@@ -170,15 +199,15 @@
 #define   ECOCHK_PPGTT_WT_HSW		(0x2<<3)
 #define   ECOCHK_PPGTT_WB_HSW		(0x3<<3)
 
-#define GAC_ECO_BITS			0x14090
+#define GAC_ECO_BITS			_MMIO(0x14090)
 #define   ECOBITS_SNB_BIT		(1<<13)
 #define   ECOBITS_PPGTT_CACHE64B	(3<<8)
 #define   ECOBITS_PPGTT_CACHE4B		(0<<8)
 
-#define GAB_CTL				0x24000
+#define GAB_CTL				_MMIO(0x24000)
 #define   GAB_CTL_CONT_AFTER_PAGEFAULT	(1<<8)
 
-#define GEN6_STOLEN_RESERVED		0x1082C0
+#define GEN6_STOLEN_RESERVED		_MMIO(0x1082C0)
 #define GEN6_STOLEN_RESERVED_ADDR_MASK	(0xFFF << 20)
 #define GEN7_STOLEN_RESERVED_ADDR_MASK	(0x3FFF << 18)
 #define GEN6_STOLEN_RESERVED_SIZE_MASK	(3 << 4)
@@ -200,6 +229,7 @@
 #define VGA_ST01_MDA 0x3ba
 #define VGA_ST01_CGA 0x3da
 
+#define _VGA_MSR_WRITE _MMIO(0x3c2)
 #define VGA_MSR_WRITE 0x3c2
 #define VGA_MSR_READ 0x3cc
 #define   VGA_MSR_MEM_EN (1<<1)
@@ -377,10 +407,12 @@
 #define MI_BATCH_BUFFER_START_GEN8	MI_INSTR(0x31, 1)
 #define   MI_BATCH_RESOURCE_STREAMER (1<<10)
 
-#define MI_PREDICATE_SRC0	(0x2400)
-#define MI_PREDICATE_SRC1	(0x2408)
+#define MI_PREDICATE_SRC0	_MMIO(0x2400)
+#define MI_PREDICATE_SRC0_UDW	_MMIO(0x2400 + 4)
+#define MI_PREDICATE_SRC1	_MMIO(0x2408)
+#define MI_PREDICATE_SRC1_UDW	_MMIO(0x2408 + 4)
 
-#define MI_PREDICATE_RESULT_2	(0x2214)
+#define MI_PREDICATE_RESULT_2	_MMIO(0x2214)
 #define  LOWER_SLICE_ENABLED	(1<<0)
 #define  LOWER_SLICE_DISABLED	(0<<0)
 
@@ -509,49 +541,61 @@
 /*
  * Registers used only by the command parser
  */
-#define BCS_SWCTRL 0x22200
+#define BCS_SWCTRL _MMIO(0x22200)
 
-#define GPGPU_THREADS_DISPATCHED        0x2290
-#define HS_INVOCATION_COUNT             0x2300
-#define DS_INVOCATION_COUNT             0x2308
-#define IA_VERTICES_COUNT               0x2310
-#define IA_PRIMITIVES_COUNT             0x2318
-#define VS_INVOCATION_COUNT             0x2320
-#define GS_INVOCATION_COUNT             0x2328
-#define GS_PRIMITIVES_COUNT             0x2330
-#define CL_INVOCATION_COUNT             0x2338
-#define CL_PRIMITIVES_COUNT             0x2340
-#define PS_INVOCATION_COUNT             0x2348
-#define PS_DEPTH_COUNT                  0x2350
+#define GPGPU_THREADS_DISPATCHED        _MMIO(0x2290)
+#define GPGPU_THREADS_DISPATCHED_UDW	_MMIO(0x2290 + 4)
+#define HS_INVOCATION_COUNT             _MMIO(0x2300)
+#define HS_INVOCATION_COUNT_UDW		_MMIO(0x2300 + 4)
+#define DS_INVOCATION_COUNT             _MMIO(0x2308)
+#define DS_INVOCATION_COUNT_UDW		_MMIO(0x2308 + 4)
+#define IA_VERTICES_COUNT               _MMIO(0x2310)
+#define IA_VERTICES_COUNT_UDW		_MMIO(0x2310 + 4)
+#define IA_PRIMITIVES_COUNT             _MMIO(0x2318)
+#define IA_PRIMITIVES_COUNT_UDW		_MMIO(0x2318 + 4)
+#define VS_INVOCATION_COUNT             _MMIO(0x2320)
+#define VS_INVOCATION_COUNT_UDW		_MMIO(0x2320 + 4)
+#define GS_INVOCATION_COUNT             _MMIO(0x2328)
+#define GS_INVOCATION_COUNT_UDW		_MMIO(0x2328 + 4)
+#define GS_PRIMITIVES_COUNT             _MMIO(0x2330)
+#define GS_PRIMITIVES_COUNT_UDW		_MMIO(0x2330 + 4)
+#define CL_INVOCATION_COUNT             _MMIO(0x2338)
+#define CL_INVOCATION_COUNT_UDW		_MMIO(0x2338 + 4)
+#define CL_PRIMITIVES_COUNT             _MMIO(0x2340)
+#define CL_PRIMITIVES_COUNT_UDW		_MMIO(0x2340 + 4)
+#define PS_INVOCATION_COUNT             _MMIO(0x2348)
+#define PS_INVOCATION_COUNT_UDW		_MMIO(0x2348 + 4)
+#define PS_DEPTH_COUNT                  _MMIO(0x2350)
+#define PS_DEPTH_COUNT_UDW		_MMIO(0x2350 + 4)
 
 /* There are the 4 64-bit counter registers, one for each stream output */
-#define GEN7_SO_NUM_PRIMS_WRITTEN(n) (0x5200 + (n) * 8)
+#define GEN7_SO_NUM_PRIMS_WRITTEN(n)		_MMIO(0x5200 + (n) * 8)
+#define GEN7_SO_NUM_PRIMS_WRITTEN_UDW(n)	_MMIO(0x5200 + (n) * 8 + 4)
 
-#define GEN7_SO_PRIM_STORAGE_NEEDED(n)  (0x5240 + (n) * 8)
+#define GEN7_SO_PRIM_STORAGE_NEEDED(n)		_MMIO(0x5240 + (n) * 8)
+#define GEN7_SO_PRIM_STORAGE_NEEDED_UDW(n)	_MMIO(0x5240 + (n) * 8 + 4)
 
-#define GEN7_3DPRIM_END_OFFSET          0x2420
-#define GEN7_3DPRIM_START_VERTEX        0x2430
-#define GEN7_3DPRIM_VERTEX_COUNT        0x2434
-#define GEN7_3DPRIM_INSTANCE_COUNT      0x2438
-#define GEN7_3DPRIM_START_INSTANCE      0x243C
-#define GEN7_3DPRIM_BASE_VERTEX         0x2440
+#define GEN7_3DPRIM_END_OFFSET          _MMIO(0x2420)
+#define GEN7_3DPRIM_START_VERTEX        _MMIO(0x2430)
+#define GEN7_3DPRIM_VERTEX_COUNT        _MMIO(0x2434)
+#define GEN7_3DPRIM_INSTANCE_COUNT      _MMIO(0x2438)
+#define GEN7_3DPRIM_START_INSTANCE      _MMIO(0x243C)
+#define GEN7_3DPRIM_BASE_VERTEX         _MMIO(0x2440)
 
-#define GEN7_GPGPU_DISPATCHDIMX         0x2500
-#define GEN7_GPGPU_DISPATCHDIMY         0x2504
-#define GEN7_GPGPU_DISPATCHDIMZ         0x2508
+#define GEN7_GPGPU_DISPATCHDIMX         _MMIO(0x2500)
+#define GEN7_GPGPU_DISPATCHDIMY         _MMIO(0x2504)
+#define GEN7_GPGPU_DISPATCHDIMZ         _MMIO(0x2508)
 
-#define OACONTROL 0x2360
+#define OACONTROL _MMIO(0x2360)
 
 #define _GEN7_PIPEA_DE_LOAD_SL	0x70068
 #define _GEN7_PIPEB_DE_LOAD_SL	0x71068
-#define GEN7_PIPE_DE_LOAD_SL(pipe) _PIPE(pipe, \
-					 _GEN7_PIPEA_DE_LOAD_SL, \
-					 _GEN7_PIPEB_DE_LOAD_SL)
+#define GEN7_PIPE_DE_LOAD_SL(pipe) _MMIO_PIPE(pipe, _GEN7_PIPEA_DE_LOAD_SL, _GEN7_PIPEB_DE_LOAD_SL)
 
 /*
  * Reset registers
  */
-#define DEBUG_RESET_I830		0x6070
+#define DEBUG_RESET_I830		_MMIO(0x6070)
 #define  DEBUG_RESET_FULL		(1<<7)
 #define  DEBUG_RESET_RENDER		(1<<8)
 #define  DEBUG_RESET_DISPLAY		(1<<9)
@@ -559,7 +603,7 @@
 /*
  * IOSF sideband
  */
-#define VLV_IOSF_DOORBELL_REQ			(VLV_DISPLAY_BASE + 0x2100)
+#define VLV_IOSF_DOORBELL_REQ			_MMIO(VLV_DISPLAY_BASE + 0x2100)
 #define   IOSF_DEVFN_SHIFT			24
 #define   IOSF_OPCODE_SHIFT			16
 #define   IOSF_PORT_SHIFT			8
@@ -576,8 +620,8 @@
 #define   IOSF_PORT_CCU				0xA9
 #define   IOSF_PORT_GPS_CORE			0x48
 #define   IOSF_PORT_FLISDSI			0x1B
-#define VLV_IOSF_DATA				(VLV_DISPLAY_BASE + 0x2104)
-#define VLV_IOSF_ADDR				(VLV_DISPLAY_BASE + 0x2108)
+#define VLV_IOSF_DATA				_MMIO(VLV_DISPLAY_BASE + 0x2104)
+#define VLV_IOSF_ADDR				_MMIO(VLV_DISPLAY_BASE + 0x2108)
 
 /* See configdb bunit SB addr map */
 #define BUNIT_REG_BISOC				0x11
@@ -609,6 +653,7 @@
 
 /* See the PUNIT HAS v0.8 for the below bits */
 enum punit_power_well {
+	/* These numbers are fixed and must match the position of the pw bits */
 	PUNIT_POWER_WELL_RENDER			= 0,
 	PUNIT_POWER_WELL_MEDIA			= 1,
 	PUNIT_POWER_WELL_DISP2D			= 3,
@@ -621,10 +666,12 @@
 	PUNIT_POWER_WELL_DPIO_RX1		= 11,
 	PUNIT_POWER_WELL_DPIO_CMN_D		= 12,
 
-	PUNIT_POWER_WELL_NUM,
+	/* Not actual bit groups. Used as IDs for lookup_power_well() */
+	PUNIT_POWER_WELL_ALWAYS_ON,
 };
 
 enum skl_disp_power_wells {
+	/* These numbers are fixed and must match the position of the pw bits */
 	SKL_DISP_PW_MISC_IO,
 	SKL_DISP_PW_DDI_A_E,
 	SKL_DISP_PW_DDI_B,
@@ -632,6 +679,10 @@
 	SKL_DISP_PW_DDI_D,
 	SKL_DISP_PW_1 = 14,
 	SKL_DISP_PW_2,
+
+	/* Not actual bit groups. Used as IDs for lookup_power_well() */
+	SKL_DISP_PW_ALWAYS_ON,
+	SKL_DISP_PW_DC_OFF,
 };
 
 #define SKL_POWER_WELL_STATE(pw) (1 << ((pw) * 2))
@@ -832,7 +883,7 @@
  */
 #define DPIO_DEVFN			0
 
-#define DPIO_CTL			(VLV_DISPLAY_BASE + 0x2110)
+#define DPIO_CTL			_MMIO(VLV_DISPLAY_BASE + 0x2110)
 #define  DPIO_MODSEL1			(1<<3) /* if ref clk b == 27 */
 #define  DPIO_MODSEL0			(1<<2) /* if ref clk a == 27 */
 #define  DPIO_SFR_BYPASS		(1<<1)
@@ -1185,9 +1236,9 @@
 #define   DPIO_UPAR_SHIFT		30
 
 /* BXT PHY registers */
-#define _BXT_PHY(phy, a, b)		_PIPE((phy), (a), (b))
+#define _BXT_PHY(phy, a, b)		_MMIO_PIPE((phy), (a), (b))
 
-#define BXT_P_CR_GT_DISP_PWRON		0x138090
+#define BXT_P_CR_GT_DISP_PWRON		_MMIO(0x138090)
 #define   GT_DISPLAY_POWER_ON(phy)	(1 << (phy))
 
 #define _PHY_CTL_FAMILY_EDP		0x64C80
@@ -1203,7 +1254,7 @@
 #define   PORT_PLL_ENABLE		(1 << 31)
 #define   PORT_PLL_LOCK			(1 << 30)
 #define   PORT_PLL_REF_SEL		(1 << 27)
-#define BXT_PORT_PLL_ENABLE(port)	_PORT(port, _PORT_PLL_A, _PORT_PLL_B)
+#define BXT_PORT_PLL_ENABLE(port)	_MMIO_PORT(port, _PORT_PLL_A, _PORT_PLL_B)
 
 #define _PORT_PLL_EBB_0_A		0x162034
 #define _PORT_PLL_EBB_0_B		0x6C034
@@ -1214,7 +1265,7 @@
 #define   PORT_PLL_P2_SHIFT		8
 #define   PORT_PLL_P2_MASK		(0x1f << PORT_PLL_P2_SHIFT)
 #define   PORT_PLL_P2(x)		((x)  << PORT_PLL_P2_SHIFT)
-#define BXT_PORT_PLL_EBB_0(port)	_PORT3(port, _PORT_PLL_EBB_0_A, \
+#define BXT_PORT_PLL_EBB_0(port)	_MMIO_PORT3(port, _PORT_PLL_EBB_0_A, \
 						_PORT_PLL_EBB_0_B,	\
 						_PORT_PLL_EBB_0_C)
 
@@ -1223,7 +1274,7 @@
 #define _PORT_PLL_EBB_4_C		0x6C344
 #define   PORT_PLL_10BIT_CLK_ENABLE	(1 << 13)
 #define   PORT_PLL_RECALIBRATE		(1 << 14)
-#define BXT_PORT_PLL_EBB_4(port)	_PORT3(port, _PORT_PLL_EBB_4_A, \
+#define BXT_PORT_PLL_EBB_4(port)	_MMIO_PORT3(port, _PORT_PLL_EBB_4_A, \
 						_PORT_PLL_EBB_4_B,	\
 						_PORT_PLL_EBB_4_C)
 
@@ -1259,7 +1310,7 @@
 #define _PORT_PLL_BASE(port)		_PORT3(port, _PORT_PLL_0_A,	\
 						_PORT_PLL_0_B,		\
 						_PORT_PLL_0_C)
-#define BXT_PORT_PLL(port, idx)		(_PORT_PLL_BASE(port) + (idx) * 4)
+#define BXT_PORT_PLL(port, idx)		_MMIO(_PORT_PLL_BASE(port) + (idx) * 4)
 
 /* BXT PHY common lane registers */
 #define _PORT_CL1CM_DW0_A		0x162000
@@ -1297,7 +1348,7 @@
 							_PORT_CL1CM_DW30_A)
 
 /* Defined for PHY0 only */
-#define BXT_PORT_CL2CM_DW6_BC		0x6C358
+#define BXT_PORT_CL2CM_DW6_BC		_MMIO(0x6C358)
 #define   DW6_OLDO_DYN_PWR_DOWN_EN	(1 << 28)
 
 /* BXT PHY Ref registers */
@@ -1337,10 +1388,10 @@
 #define _PORT_PCS_DW10_GRP_A		0x162C28
 #define _PORT_PCS_DW10_GRP_B		0x6CC28
 #define _PORT_PCS_DW10_GRP_C		0x6CE28
-#define BXT_PORT_PCS_DW10_LN01(port)	_PORT3(port, _PORT_PCS_DW10_LN01_A, \
+#define BXT_PORT_PCS_DW10_LN01(port)	_MMIO_PORT3(port, _PORT_PCS_DW10_LN01_A, \
 						     _PORT_PCS_DW10_LN01_B, \
 						     _PORT_PCS_DW10_LN01_C)
-#define BXT_PORT_PCS_DW10_GRP(port)	_PORT3(port, _PORT_PCS_DW10_GRP_A,  \
+#define BXT_PORT_PCS_DW10_GRP(port)	_MMIO_PORT3(port, _PORT_PCS_DW10_GRP_A,  \
 						     _PORT_PCS_DW10_GRP_B,  \
 						     _PORT_PCS_DW10_GRP_C)
 #define   TX2_SWING_CALC_INIT		(1 << 31)
@@ -1357,13 +1408,13 @@
 #define _PORT_PCS_DW12_GRP_C		0x6CE30
 #define   LANESTAGGER_STRAP_OVRD	(1 << 6)
 #define   LANE_STAGGER_MASK		0x1F
-#define BXT_PORT_PCS_DW12_LN01(port)	_PORT3(port, _PORT_PCS_DW12_LN01_A, \
+#define BXT_PORT_PCS_DW12_LN01(port)	_MMIO_PORT3(port, _PORT_PCS_DW12_LN01_A, \
 						     _PORT_PCS_DW12_LN01_B, \
 						     _PORT_PCS_DW12_LN01_C)
-#define BXT_PORT_PCS_DW12_LN23(port)	_PORT3(port, _PORT_PCS_DW12_LN23_A, \
+#define BXT_PORT_PCS_DW12_LN23(port)	_MMIO_PORT3(port, _PORT_PCS_DW12_LN23_A, \
 						     _PORT_PCS_DW12_LN23_B, \
 						     _PORT_PCS_DW12_LN23_C)
-#define BXT_PORT_PCS_DW12_GRP(port)	_PORT3(port, _PORT_PCS_DW12_GRP_A, \
+#define BXT_PORT_PCS_DW12_GRP(port)	_MMIO_PORT3(port, _PORT_PCS_DW12_GRP_A, \
 						     _PORT_PCS_DW12_GRP_B, \
 						     _PORT_PCS_DW12_GRP_C)
 
@@ -1377,10 +1428,10 @@
 #define _PORT_TX_DW2_GRP_A		0x162D08
 #define _PORT_TX_DW2_GRP_B		0x6CD08
 #define _PORT_TX_DW2_GRP_C		0x6CF08
-#define BXT_PORT_TX_DW2_GRP(port)	_PORT3(port, _PORT_TX_DW2_GRP_A,  \
+#define BXT_PORT_TX_DW2_GRP(port)	_MMIO_PORT3(port, _PORT_TX_DW2_GRP_A,  \
 						     _PORT_TX_DW2_GRP_B,  \
 						     _PORT_TX_DW2_GRP_C)
-#define BXT_PORT_TX_DW2_LN0(port)	_PORT3(port, _PORT_TX_DW2_LN0_A,  \
+#define BXT_PORT_TX_DW2_LN0(port)	_MMIO_PORT3(port, _PORT_TX_DW2_LN0_A,  \
 						     _PORT_TX_DW2_LN0_B,  \
 						     _PORT_TX_DW2_LN0_C)
 #define   MARGIN_000_SHIFT		16
@@ -1394,10 +1445,10 @@
 #define _PORT_TX_DW3_GRP_A		0x162D0C
 #define _PORT_TX_DW3_GRP_B		0x6CD0C
 #define _PORT_TX_DW3_GRP_C		0x6CF0C
-#define BXT_PORT_TX_DW3_GRP(port)	_PORT3(port, _PORT_TX_DW3_GRP_A,  \
+#define BXT_PORT_TX_DW3_GRP(port)	_MMIO_PORT3(port, _PORT_TX_DW3_GRP_A,  \
 						     _PORT_TX_DW3_GRP_B,  \
 						     _PORT_TX_DW3_GRP_C)
-#define BXT_PORT_TX_DW3_LN0(port)	_PORT3(port, _PORT_TX_DW3_LN0_A,  \
+#define BXT_PORT_TX_DW3_LN0(port)	_MMIO_PORT3(port, _PORT_TX_DW3_LN0_A,  \
 						     _PORT_TX_DW3_LN0_B,  \
 						     _PORT_TX_DW3_LN0_C)
 #define   SCALE_DCOMP_METHOD		(1 << 26)
@@ -1409,10 +1460,10 @@
 #define _PORT_TX_DW4_GRP_A		0x162D10
 #define _PORT_TX_DW4_GRP_B		0x6CD10
 #define _PORT_TX_DW4_GRP_C		0x6CF10
-#define BXT_PORT_TX_DW4_LN0(port)	_PORT3(port, _PORT_TX_DW4_LN0_A,  \
+#define BXT_PORT_TX_DW4_LN0(port)	_MMIO_PORT3(port, _PORT_TX_DW4_LN0_A,  \
 						     _PORT_TX_DW4_LN0_B,  \
 						     _PORT_TX_DW4_LN0_C)
-#define BXT_PORT_TX_DW4_GRP(port)	_PORT3(port, _PORT_TX_DW4_GRP_A,  \
+#define BXT_PORT_TX_DW4_GRP(port)	_MMIO_PORT3(port, _PORT_TX_DW4_GRP_A,  \
 						     _PORT_TX_DW4_GRP_B,  \
 						     _PORT_TX_DW4_GRP_C)
 #define   DEEMPH_SHIFT			24
@@ -1423,17 +1474,17 @@
 #define _PORT_TX_DW14_LN0_C		0x6C938
 #define   LATENCY_OPTIM_SHIFT		30
 #define   LATENCY_OPTIM			(1 << LATENCY_OPTIM_SHIFT)
-#define BXT_PORT_TX_DW14_LN(port, lane)	(_PORT3((port), _PORT_TX_DW14_LN0_A,   \
+#define BXT_PORT_TX_DW14_LN(port, lane)	_MMIO(_PORT3((port), _PORT_TX_DW14_LN0_A,   \
 							_PORT_TX_DW14_LN0_B,   \
 							_PORT_TX_DW14_LN0_C) + \
 					 _BXT_LANE_OFFSET(lane))
 
 /* UAIMI scratch pad register 1 */
-#define UAIMI_SPR1			0x4F074
+#define UAIMI_SPR1			_MMIO(0x4F074)
 /* SKL VccIO mask */
 #define SKL_VCCIO_MASK			0x1
 /* SKL balance leg register */
-#define DISPIO_CR_TX_BMU_CR0		0x6C00C
+#define DISPIO_CR_TX_BMU_CR0		_MMIO(0x6C00C)
 /* I_boost values */
 #define BALANCE_LEG_SHIFT(port)		(8+3*(port))
 #define BALANCE_LEG_MASK(port)		(7<<(8+3*(port)))
@@ -1450,7 +1501,7 @@
  * [0-15] @ 0x100000 gen6,vlv,chv
  * [0-31] @ 0x100000 gen7+
  */
-#define FENCE_REG(i)			(0x2000 + (((i) & 8) << 9) + ((i) & 7) * 4)
+#define FENCE_REG(i)			_MMIO(0x2000 + (((i) & 8) << 9) + ((i) & 7) * 4)
 #define   I830_FENCE_START_MASK		0x07f80000
 #define   I830_FENCE_TILING_Y_SHIFT	12
 #define   I830_FENCE_SIZE_BITS(size)	((ffs((size) >> 19) - 1) << 8)
@@ -1463,21 +1514,21 @@
 #define   I915_FENCE_START_MASK		0x0ff00000
 #define   I915_FENCE_SIZE_BITS(size)	((ffs((size) >> 20) - 1) << 8)
 
-#define FENCE_REG_965_LO(i)		(0x03000 + (i) * 8)
-#define FENCE_REG_965_HI(i)		(0x03000 + (i) * 8 + 4)
+#define FENCE_REG_965_LO(i)		_MMIO(0x03000 + (i) * 8)
+#define FENCE_REG_965_HI(i)		_MMIO(0x03000 + (i) * 8 + 4)
 #define   I965_FENCE_PITCH_SHIFT	2
 #define   I965_FENCE_TILING_Y_SHIFT	1
 #define   I965_FENCE_REG_VALID		(1<<0)
 #define   I965_FENCE_MAX_PITCH_VAL	0x0400
 
-#define FENCE_REG_GEN6_LO(i)	(0x100000 + (i) * 8)
-#define FENCE_REG_GEN6_HI(i)	(0x100000 + (i) * 8 + 4)
+#define FENCE_REG_GEN6_LO(i)		_MMIO(0x100000 + (i) * 8)
+#define FENCE_REG_GEN6_HI(i)		_MMIO(0x100000 + (i) * 8 + 4)
 #define   GEN6_FENCE_PITCH_SHIFT	32
 #define   GEN7_FENCE_MAX_PITCH_VAL	0x0800
 
 
 /* control register for cpu gtt access */
-#define TILECTL				0x101000
+#define TILECTL				_MMIO(0x101000)
 #define   TILECTL_SWZCTL			(1 << 0)
 #define   TILECTL_TLBPF			(1 << 1)
 #define   TILECTL_TLB_PREFETCH_DIS	(1 << 2)
@@ -1486,30 +1537,30 @@
 /*
  * Instruction and interrupt control regs
  */
-#define PGTBL_CTL	0x02020
+#define PGTBL_CTL	_MMIO(0x02020)
 #define   PGTBL_ADDRESS_LO_MASK	0xfffff000 /* bits [31:12] */
 #define   PGTBL_ADDRESS_HI_MASK	0x000000f0 /* bits [35:32] (gen4) */
-#define PGTBL_ER	0x02024
-#define PRB0_BASE (0x2030-0x30)
-#define PRB1_BASE (0x2040-0x30) /* 830,gen3 */
-#define PRB2_BASE (0x2050-0x30) /* gen3 */
-#define SRB0_BASE (0x2100-0x30) /* gen2 */
-#define SRB1_BASE (0x2110-0x30) /* gen2 */
-#define SRB2_BASE (0x2120-0x30) /* 830 */
-#define SRB3_BASE (0x2130-0x30) /* 830 */
+#define PGTBL_ER	_MMIO(0x02024)
+#define PRB0_BASE	(0x2030-0x30)
+#define PRB1_BASE	(0x2040-0x30) /* 830,gen3 */
+#define PRB2_BASE	(0x2050-0x30) /* gen3 */
+#define SRB0_BASE	(0x2100-0x30) /* gen2 */
+#define SRB1_BASE	(0x2110-0x30) /* gen2 */
+#define SRB2_BASE	(0x2120-0x30) /* 830 */
+#define SRB3_BASE	(0x2130-0x30) /* 830 */
 #define RENDER_RING_BASE	0x02000
 #define BSD_RING_BASE		0x04000
 #define GEN6_BSD_RING_BASE	0x12000
 #define GEN8_BSD2_RING_BASE	0x1c000
 #define VEBOX_RING_BASE		0x1a000
 #define BLT_RING_BASE		0x22000
-#define RING_TAIL(base)		((base)+0x30)
-#define RING_HEAD(base)		((base)+0x34)
-#define RING_START(base)	((base)+0x38)
-#define RING_CTL(base)		((base)+0x3c)
-#define RING_SYNC_0(base)	((base)+0x40)
-#define RING_SYNC_1(base)	((base)+0x44)
-#define RING_SYNC_2(base)	((base)+0x48)
+#define RING_TAIL(base)		_MMIO((base)+0x30)
+#define RING_HEAD(base)		_MMIO((base)+0x34)
+#define RING_START(base)	_MMIO((base)+0x38)
+#define RING_CTL(base)		_MMIO((base)+0x3c)
+#define RING_SYNC_0(base)	_MMIO((base)+0x40)
+#define RING_SYNC_1(base)	_MMIO((base)+0x44)
+#define RING_SYNC_2(base)	_MMIO((base)+0x48)
 #define GEN6_RVSYNC	(RING_SYNC_0(RENDER_RING_BASE))
 #define GEN6_RBSYNC	(RING_SYNC_1(RENDER_RING_BASE))
 #define GEN6_RVESYNC	(RING_SYNC_2(RENDER_RING_BASE))
@@ -1522,51 +1573,52 @@
 #define GEN6_VEBSYNC	(RING_SYNC_0(VEBOX_RING_BASE))
 #define GEN6_VERSYNC	(RING_SYNC_1(VEBOX_RING_BASE))
 #define GEN6_VEVSYNC	(RING_SYNC_2(VEBOX_RING_BASE))
-#define GEN6_NOSYNC 0
-#define RING_PSMI_CTL(base)	((base)+0x50)
-#define RING_MAX_IDLE(base)	((base)+0x54)
-#define RING_HWS_PGA(base)	((base)+0x80)
-#define RING_HWS_PGA_GEN6(base)	((base)+0x2080)
-#define RING_RESET_CTL(base)	((base)+0xd0)
+#define GEN6_NOSYNC	INVALID_MMIO_REG
+#define RING_PSMI_CTL(base)	_MMIO((base)+0x50)
+#define RING_MAX_IDLE(base)	_MMIO((base)+0x54)
+#define RING_HWS_PGA(base)	_MMIO((base)+0x80)
+#define RING_HWS_PGA_GEN6(base)	_MMIO((base)+0x2080)
+#define RING_RESET_CTL(base)	_MMIO((base)+0xd0)
 #define   RESET_CTL_REQUEST_RESET  (1 << 0)
 #define   RESET_CTL_READY_TO_RESET (1 << 1)
 
-#define HSW_GTT_CACHE_EN	0x4024
+#define HSW_GTT_CACHE_EN	_MMIO(0x4024)
 #define   GTT_CACHE_EN_ALL	0xF0007FFF
-#define GEN7_WR_WATERMARK	0x4028
-#define GEN7_GFX_PRIO_CTRL	0x402C
-#define ARB_MODE		0x4030
+#define GEN7_WR_WATERMARK	_MMIO(0x4028)
+#define GEN7_GFX_PRIO_CTRL	_MMIO(0x402C)
+#define ARB_MODE		_MMIO(0x4030)
 #define   ARB_MODE_SWIZZLE_SNB	(1<<4)
 #define   ARB_MODE_SWIZZLE_IVB	(1<<5)
-#define GEN7_GFX_PEND_TLB0	0x4034
-#define GEN7_GFX_PEND_TLB1	0x4038
+#define GEN7_GFX_PEND_TLB0	_MMIO(0x4034)
+#define GEN7_GFX_PEND_TLB1	_MMIO(0x4038)
 /* L3, CVS, ZTLB, RCC, CASC LRA min, max values */
-#define GEN7_LRA_LIMITS(i)	(0x403C + (i) * 4)
+#define GEN7_LRA_LIMITS(i)	_MMIO(0x403C + (i) * 4)
 #define GEN7_LRA_LIMITS_REG_NUM	13
-#define GEN7_MEDIA_MAX_REQ_COUNT	0x4070
-#define GEN7_GFX_MAX_REQ_COUNT		0x4074
+#define GEN7_MEDIA_MAX_REQ_COUNT	_MMIO(0x4070)
+#define GEN7_GFX_MAX_REQ_COUNT		_MMIO(0x4074)
 
-#define GAMTARBMODE		0x04a08
+#define GAMTARBMODE		_MMIO(0x04a08)
 #define   ARB_MODE_BWGTLB_DISABLE (1<<9)
 #define   ARB_MODE_SWIZZLE_BDW	(1<<1)
-#define RENDER_HWS_PGA_GEN7	(0x04080)
-#define RING_FAULT_REG(ring)	(0x4094 + 0x100*(ring)->id)
+#define RENDER_HWS_PGA_GEN7	_MMIO(0x04080)
+#define RING_FAULT_REG(ring)	_MMIO(0x4094 + 0x100*(ring)->id)
 #define   RING_FAULT_GTTSEL_MASK (1<<11)
 #define   RING_FAULT_SRCID(x)	(((x) >> 3) & 0xff)
 #define   RING_FAULT_FAULT_TYPE(x) (((x) >> 1) & 0x3)
 #define   RING_FAULT_VALID	(1<<0)
-#define DONE_REG		0x40b0
-#define GEN8_PRIVATE_PAT_LO	0x40e0
-#define GEN8_PRIVATE_PAT_HI	(0x40e0 + 4)
-#define BSD_HWS_PGA_GEN7	(0x04180)
-#define BLT_HWS_PGA_GEN7	(0x04280)
-#define VEBOX_HWS_PGA_GEN7	(0x04380)
-#define RING_ACTHD(base)	((base)+0x74)
-#define RING_ACTHD_UDW(base)	((base)+0x5c)
-#define RING_NOPID(base)	((base)+0x94)
-#define RING_IMR(base)		((base)+0xa8)
-#define RING_HWSTAM(base)	((base)+0x98)
-#define RING_TIMESTAMP(base)	((base)+0x358)
+#define DONE_REG		_MMIO(0x40b0)
+#define GEN8_PRIVATE_PAT_LO	_MMIO(0x40e0)
+#define GEN8_PRIVATE_PAT_HI	_MMIO(0x40e0 + 4)
+#define BSD_HWS_PGA_GEN7	_MMIO(0x04180)
+#define BLT_HWS_PGA_GEN7	_MMIO(0x04280)
+#define VEBOX_HWS_PGA_GEN7	_MMIO(0x04380)
+#define RING_ACTHD(base)	_MMIO((base)+0x74)
+#define RING_ACTHD_UDW(base)	_MMIO((base)+0x5c)
+#define RING_NOPID(base)	_MMIO((base)+0x94)
+#define RING_IMR(base)		_MMIO((base)+0xa8)
+#define RING_HWSTAM(base)	_MMIO((base)+0x98)
+#define RING_TIMESTAMP(base)		_MMIO((base)+0x358)
+#define RING_TIMESTAMP_UDW(base)	_MMIO((base)+0x358 + 4)
 #define   TAIL_ADDR		0x001FFFF8
 #define   HEAD_WRAP_COUNT	0xFFE00000
 #define   HEAD_WRAP_ONE		0x00200000
@@ -1583,57 +1635,65 @@
 #define   RING_WAIT		(1<<11) /* gen3+, PRBx_CTL */
 #define   RING_WAIT_SEMAPHORE	(1<<10) /* gen6+ */
 
-#define GEN7_TLB_RD_ADDR	0x4700
+#define GEN7_TLB_RD_ADDR	_MMIO(0x4700)
 
 #if 0
-#define PRB0_TAIL	0x02030
-#define PRB0_HEAD	0x02034
-#define PRB0_START	0x02038
-#define PRB0_CTL	0x0203c
-#define PRB1_TAIL	0x02040 /* 915+ only */
-#define PRB1_HEAD	0x02044 /* 915+ only */
-#define PRB1_START	0x02048 /* 915+ only */
-#define PRB1_CTL	0x0204c /* 915+ only */
+#define PRB0_TAIL	_MMIO(0x2030)
+#define PRB0_HEAD	_MMIO(0x2034)
+#define PRB0_START	_MMIO(0x2038)
+#define PRB0_CTL	_MMIO(0x203c)
+#define PRB1_TAIL	_MMIO(0x2040) /* 915+ only */
+#define PRB1_HEAD	_MMIO(0x2044) /* 915+ only */
+#define PRB1_START	_MMIO(0x2048) /* 915+ only */
+#define PRB1_CTL	_MMIO(0x204c) /* 915+ only */
 #endif
-#define IPEIR_I965	0x02064
-#define IPEHR_I965	0x02068
-#define GEN7_SC_INSTDONE	0x07100
-#define GEN7_SAMPLER_INSTDONE	0x0e160
-#define GEN7_ROW_INSTDONE	0x0e164
+#define IPEIR_I965	_MMIO(0x2064)
+#define IPEHR_I965	_MMIO(0x2068)
+#define GEN7_SC_INSTDONE	_MMIO(0x7100)
+#define GEN7_SAMPLER_INSTDONE	_MMIO(0xe160)
+#define GEN7_ROW_INSTDONE	_MMIO(0xe164)
 #define I915_NUM_INSTDONE_REG	4
-#define RING_IPEIR(base)	((base)+0x64)
-#define RING_IPEHR(base)	((base)+0x68)
+#define RING_IPEIR(base)	_MMIO((base)+0x64)
+#define RING_IPEHR(base)	_MMIO((base)+0x68)
 /*
  * On GEN4, only the render ring INSTDONE exists and has a different
  * layout than the GEN7+ version.
  * The GEN2 counterpart of this register is GEN2_INSTDONE.
  */
-#define RING_INSTDONE(base)	((base)+0x6c)
-#define RING_INSTPS(base)	((base)+0x70)
-#define RING_DMA_FADD(base)	((base)+0x78)
-#define RING_DMA_FADD_UDW(base)	((base)+0x60) /* gen8+ */
-#define RING_INSTPM(base)	((base)+0xc0)
-#define RING_MI_MODE(base)	((base)+0x9c)
-#define INSTPS		0x02070 /* 965+ only */
-#define GEN4_INSTDONE1	0x0207c /* 965+ only, aka INSTDONE_2 on SNB */
-#define ACTHD_I965	0x02074
-#define HWS_PGA		0x02080
+#define RING_INSTDONE(base)	_MMIO((base)+0x6c)
+#define RING_INSTPS(base)	_MMIO((base)+0x70)
+#define RING_DMA_FADD(base)	_MMIO((base)+0x78)
+#define RING_DMA_FADD_UDW(base)	_MMIO((base)+0x60) /* gen8+ */
+#define RING_INSTPM(base)	_MMIO((base)+0xc0)
+#define RING_MI_MODE(base)	_MMIO((base)+0x9c)
+#define INSTPS		_MMIO(0x2070) /* 965+ only */
+#define GEN4_INSTDONE1	_MMIO(0x207c) /* 965+ only, aka INSTDONE_2 on SNB */
+#define ACTHD_I965	_MMIO(0x2074)
+#define HWS_PGA		_MMIO(0x2080)
 #define HWS_ADDRESS_MASK	0xfffff000
 #define HWS_START_ADDRESS_SHIFT	4
-#define PWRCTXA		0x2088 /* 965GM+ only */
+#define PWRCTXA		_MMIO(0x2088) /* 965GM+ only */
 #define   PWRCTX_EN	(1<<0)
-#define IPEIR		0x02088
-#define IPEHR		0x0208c
-#define GEN2_INSTDONE	0x02090
-#define NOPID		0x02094
-#define HWSTAM		0x02098
-#define DMA_FADD_I8XX	0x020d0
-#define RING_BBSTATE(base)	((base)+0x110)
-#define RING_BBADDR(base)	((base)+0x140)
-#define RING_BBADDR_UDW(base)	((base)+0x168) /* gen8+ */
+#define IPEIR		_MMIO(0x2088)
+#define IPEHR		_MMIO(0x208c)
+#define GEN2_INSTDONE	_MMIO(0x2090)
+#define NOPID		_MMIO(0x2094)
+#define HWSTAM		_MMIO(0x2098)
+#define DMA_FADD_I8XX	_MMIO(0x20d0)
+#define RING_BBSTATE(base)	_MMIO((base)+0x110)
+#define   RING_BB_PPGTT		(1 << 5)
+#define RING_SBBADDR(base)	_MMIO((base)+0x114) /* hsw+ */
+#define RING_SBBSTATE(base)	_MMIO((base)+0x118) /* hsw+ */
+#define RING_SBBADDR_UDW(base)	_MMIO((base)+0x11c) /* gen8+ */
+#define RING_BBADDR(base)	_MMIO((base)+0x140)
+#define RING_BBADDR_UDW(base)	_MMIO((base)+0x168) /* gen8+ */
+#define RING_BB_PER_CTX_PTR(base)	_MMIO((base)+0x1c0) /* gen8+ */
+#define RING_INDIRECT_CTX(base)		_MMIO((base)+0x1c4) /* gen8+ */
+#define RING_INDIRECT_CTX_OFFSET(base)	_MMIO((base)+0x1c8) /* gen8+ */
+#define RING_CTX_TIMESTAMP(base)	_MMIO((base)+0x3a8) /* gen8+ */
 
-#define ERROR_GEN6	0x040a0
-#define GEN7_ERR_INT	0x44040
+#define ERROR_GEN6	_MMIO(0x40a0)
+#define GEN7_ERR_INT	_MMIO(0x44040)
 #define   ERR_INT_POISON		(1<<31)
 #define   ERR_INT_MMIO_UNCLAIMED	(1<<13)
 #define   ERR_INT_PIPE_CRC_DONE_C	(1<<8)
@@ -1645,13 +1705,13 @@
 #define   ERR_INT_FIFO_UNDERRUN_A	(1<<0)
 #define   ERR_INT_FIFO_UNDERRUN(pipe)	(1<<((pipe)*3))
 
-#define GEN8_FAULT_TLB_DATA0		0x04b10
-#define GEN8_FAULT_TLB_DATA1		0x04b14
+#define GEN8_FAULT_TLB_DATA0		_MMIO(0x4b10)
+#define GEN8_FAULT_TLB_DATA1		_MMIO(0x4b14)
 
-#define FPGA_DBG		0x42300
+#define FPGA_DBG		_MMIO(0x42300)
 #define   FPGA_DBG_RM_NOCLAIM	(1<<31)
 
-#define DERRMR		0x44050
+#define DERRMR		_MMIO(0x44050)
 /* Note that HBLANK events are reserved on bdw+ */
 #define   DERRMR_PIPEA_SCANLINE		(1<<0)
 #define   DERRMR_PIPEA_PRI_FLIP_DONE	(1<<1)
@@ -1675,29 +1735,29 @@
  * for various sorts of correct behavior.  The top 16 bits of each are
  * the enables for writing to the corresponding low bit.
  */
-#define _3D_CHICKEN	0x02084
+#define _3D_CHICKEN	_MMIO(0x2084)
 #define  _3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB	(1 << 10)
-#define _3D_CHICKEN2	0x0208c
+#define _3D_CHICKEN2	_MMIO(0x208c)
 /* Disables pipelining of read flushes past the SF-WIZ interface.
  * Required on all Ironlake steppings according to the B-Spec, but the
  * particular danger of not doing so is not specified.
  */
 # define _3D_CHICKEN2_WM_READ_PIPELINED			(1 << 14)
-#define _3D_CHICKEN3	0x02090
+#define _3D_CHICKEN3	_MMIO(0x2090)
 #define  _3D_CHICKEN_SF_DISABLE_OBJEND_CULL		(1 << 10)
 #define  _3D_CHICKEN3_SF_DISABLE_FASTCLIP_CULL		(1 << 5)
 #define  _3D_CHICKEN_SDE_LIMIT_FIFO_POLY_DEPTH(x)	((x)<<1) /* gen8+ */
 #define  _3D_CHICKEN3_SF_DISABLE_PIPELINED_ATTR_FETCH	(1 << 1) /* gen6 */
 
-#define MI_MODE		0x0209c
+#define MI_MODE		_MMIO(0x209c)
 # define VS_TIMER_DISPATCH				(1 << 6)
 # define MI_FLUSH_ENABLE				(1 << 12)
 # define ASYNC_FLIP_PERF_DISABLE			(1 << 14)
 # define MODE_IDLE					(1 << 9)
 # define STOP_RING					(1 << 8)
 
-#define GEN6_GT_MODE	0x20d0
-#define GEN7_GT_MODE	0x7008
+#define GEN6_GT_MODE	_MMIO(0x20d0)
+#define GEN7_GT_MODE	_MMIO(0x7008)
 #define   GEN6_WIZ_HASHING(hi, lo)			(((hi) << 9) | ((lo) << 7))
 #define   GEN6_WIZ_HASHING_8x8				GEN6_WIZ_HASHING(0, 0)
 #define   GEN6_WIZ_HASHING_8x4				GEN6_WIZ_HASHING(0, 1)
@@ -1707,9 +1767,9 @@
 #define   GEN9_IZ_HASHING_MASK(slice)			(0x3 << ((slice) * 2))
 #define   GEN9_IZ_HASHING(slice, val)			((val) << ((slice) * 2))
 
-#define GFX_MODE	0x02520
-#define GFX_MODE_GEN7	0x0229c
-#define RING_MODE_GEN7(ring)	((ring)->mmio_base+0x29c)
+#define GFX_MODE	_MMIO(0x2520)
+#define GFX_MODE_GEN7	_MMIO(0x229c)
+#define RING_MODE_GEN7(ring)	_MMIO((ring)->mmio_base+0x29c)
 #define   GFX_RUN_LIST_ENABLE		(1<<15)
 #define   GFX_INTERRUPT_STEERING	(1<<14)
 #define   GFX_TLB_INVALIDATE_EXPLICIT	(1<<13)
@@ -1727,36 +1787,36 @@
 #define VLV_DISPLAY_BASE 0x180000
 #define VLV_MIPI_BASE VLV_DISPLAY_BASE
 
-#define VLV_GU_CTL0	(VLV_DISPLAY_BASE + 0x2030)
-#define VLV_GU_CTL1	(VLV_DISPLAY_BASE + 0x2034)
-#define SCPD0		0x0209c /* 915+ only */
-#define IER		0x020a0
-#define IIR		0x020a4
-#define IMR		0x020a8
-#define ISR		0x020ac
-#define VLV_GUNIT_CLOCK_GATE	(VLV_DISPLAY_BASE + 0x2060)
+#define VLV_GU_CTL0	_MMIO(VLV_DISPLAY_BASE + 0x2030)
+#define VLV_GU_CTL1	_MMIO(VLV_DISPLAY_BASE + 0x2034)
+#define SCPD0		_MMIO(0x209c) /* 915+ only */
+#define IER		_MMIO(0x20a0)
+#define IIR		_MMIO(0x20a4)
+#define IMR		_MMIO(0x20a8)
+#define ISR		_MMIO(0x20ac)
+#define VLV_GUNIT_CLOCK_GATE	_MMIO(VLV_DISPLAY_BASE + 0x2060)
 #define   GINT_DIS		(1<<22)
 #define   GCFG_DIS		(1<<8)
-#define VLV_GUNIT_CLOCK_GATE2	(VLV_DISPLAY_BASE + 0x2064)
-#define VLV_IIR_RW	(VLV_DISPLAY_BASE + 0x2084)
-#define VLV_IER		(VLV_DISPLAY_BASE + 0x20a0)
-#define VLV_IIR		(VLV_DISPLAY_BASE + 0x20a4)
-#define VLV_IMR		(VLV_DISPLAY_BASE + 0x20a8)
-#define VLV_ISR		(VLV_DISPLAY_BASE + 0x20ac)
-#define VLV_PCBR	(VLV_DISPLAY_BASE + 0x2120)
+#define VLV_GUNIT_CLOCK_GATE2	_MMIO(VLV_DISPLAY_BASE + 0x2064)
+#define VLV_IIR_RW	_MMIO(VLV_DISPLAY_BASE + 0x2084)
+#define VLV_IER		_MMIO(VLV_DISPLAY_BASE + 0x20a0)
+#define VLV_IIR		_MMIO(VLV_DISPLAY_BASE + 0x20a4)
+#define VLV_IMR		_MMIO(VLV_DISPLAY_BASE + 0x20a8)
+#define VLV_ISR		_MMIO(VLV_DISPLAY_BASE + 0x20ac)
+#define VLV_PCBR	_MMIO(VLV_DISPLAY_BASE + 0x2120)
 #define VLV_PCBR_ADDR_SHIFT	12
 
 #define   DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */
-#define EIR		0x020b0
-#define EMR		0x020b4
-#define ESR		0x020b8
+#define EIR		_MMIO(0x20b0)
+#define EMR		_MMIO(0x20b4)
+#define ESR		_MMIO(0x20b8)
 #define   GM45_ERROR_PAGE_TABLE				(1<<5)
 #define   GM45_ERROR_MEM_PRIV				(1<<4)
 #define   I915_ERROR_PAGE_TABLE				(1<<4)
 #define   GM45_ERROR_CP_PRIV				(1<<3)
 #define   I915_ERROR_MEMORY_REFRESH			(1<<1)
 #define   I915_ERROR_INSTRUCTION			(1<<0)
-#define INSTPM	        0x020c0
+#define INSTPM	        _MMIO(0x20c0)
 #define   INSTPM_SELF_EN (1<<12) /* 915GM only */
 #define   INSTPM_AGPBUSY_INT_EN (1<<11) /* gen3: when disabled, pending interrupts
 					will not assert AGPBUSY# and will only
@@ -1764,14 +1824,14 @@
 #define   INSTPM_FORCE_ORDERING				(1<<7) /* GEN6+ */
 #define   INSTPM_TLB_INVALIDATE	(1<<9)
 #define   INSTPM_SYNC_FLUSH	(1<<5)
-#define ACTHD	        0x020c8
-#define MEM_MODE	0x020cc
+#define ACTHD	        _MMIO(0x20c8)
+#define MEM_MODE	_MMIO(0x20cc)
 #define   MEM_DISPLAY_B_TRICKLE_FEED_DISABLE (1<<3) /* 830 only */
 #define   MEM_DISPLAY_A_TRICKLE_FEED_DISABLE (1<<2) /* 830/845 only */
 #define   MEM_DISPLAY_TRICKLE_FEED_DISABLE (1<<2) /* 85x only */
-#define FW_BLC		0x020d8
-#define FW_BLC2		0x020dc
-#define FW_BLC_SELF	0x020e0 /* 915+ only */
+#define FW_BLC		_MMIO(0x20d8)
+#define FW_BLC2		_MMIO(0x20dc)
+#define FW_BLC_SELF	_MMIO(0x20e0) /* 915+ only */
 #define   FW_BLC_SELF_EN_MASK      (1<<31)
 #define   FW_BLC_SELF_FIFO_MASK    (1<<16) /* 945 only */
 #define   FW_BLC_SELF_EN           (1<<15) /* 945 only */
@@ -1779,7 +1839,7 @@
 #define MM_FIFO_WATERMARK   0x0001F000
 #define LM_BURST_LENGTH     0x00000700
 #define LM_FIFO_WATERMARK   0x0000001F
-#define MI_ARB_STATE	0x020e4 /* 915+ only */
+#define MI_ARB_STATE	_MMIO(0x20e4) /* 915+ only */
 
 /* Make render/texture TLB fetches lower priorty than associated data
  *   fetches. This is not turned on by default
@@ -1843,11 +1903,11 @@
 #define   MI_ARB_DISPLAY_PRIORITY_A_B		(0 << 0)	/* display A > display B */
 #define   MI_ARB_DISPLAY_PRIORITY_B_A		(1 << 0)	/* display B > display A */
 
-#define MI_STATE	0x020e4 /* gen2 only */
+#define MI_STATE	_MMIO(0x20e4) /* gen2 only */
 #define   MI_AGPBUSY_INT_EN			(1 << 1) /* 85x only */
 #define   MI_AGPBUSY_830_MODE			(1 << 0) /* 85x only */
 
-#define CACHE_MODE_0	0x02120 /* 915+ only */
+#define CACHE_MODE_0	_MMIO(0x2120) /* 915+ only */
 #define   CM0_PIPELINED_RENDER_FLUSH_DISABLE (1<<8)
 #define   CM0_IZ_OPT_DISABLE      (1<<6)
 #define   CM0_ZR_OPT_DISABLE      (1<<5)
@@ -1856,32 +1916,32 @@
 #define   CM0_COLOR_EVICT_DISABLE (1<<3)
 #define   CM0_DEPTH_WRITE_DISABLE (1<<1)
 #define   CM0_RC_OP_FLUSH_DISABLE (1<<0)
-#define GFX_FLSH_CNTL	0x02170 /* 915+ only */
-#define GFX_FLSH_CNTL_GEN6	0x101008
+#define GFX_FLSH_CNTL	_MMIO(0x2170) /* 915+ only */
+#define GFX_FLSH_CNTL_GEN6	_MMIO(0x101008)
 #define   GFX_FLSH_CNTL_EN	(1<<0)
-#define ECOSKPD		0x021d0
+#define ECOSKPD		_MMIO(0x21d0)
 #define   ECO_GATING_CX_ONLY	(1<<3)
 #define   ECO_FLIP_DONE		(1<<0)
 
-#define CACHE_MODE_0_GEN7	0x7000 /* IVB+ */
+#define CACHE_MODE_0_GEN7	_MMIO(0x7000) /* IVB+ */
 #define RC_OP_FLUSH_ENABLE (1<<0)
 #define   HIZ_RAW_STALL_OPT_DISABLE (1<<2)
-#define CACHE_MODE_1		0x7004 /* IVB+ */
+#define CACHE_MODE_1		_MMIO(0x7004) /* IVB+ */
 #define   PIXEL_SUBSPAN_COLLECT_OPT_DISABLE	(1<<6)
 #define   GEN8_4x4_STC_OPTIMIZATION_DISABLE	(1<<6)
 #define   GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE	(1<<1)
 
-#define GEN6_BLITTER_ECOSKPD	0x221d0
+#define GEN6_BLITTER_ECOSKPD	_MMIO(0x221d0)
 #define   GEN6_BLITTER_LOCK_SHIFT			16
 #define   GEN6_BLITTER_FBC_NOTIFY			(1<<3)
 
-#define GEN6_RC_SLEEP_PSMI_CONTROL	0x2050
+#define GEN6_RC_SLEEP_PSMI_CONTROL	_MMIO(0x2050)
 #define   GEN6_PSMI_SLEEP_MSG_DISABLE	(1 << 0)
 #define   GEN8_RC_SEMA_IDLE_MSG_DISABLE	(1 << 12)
 #define   GEN8_FF_DOP_CLOCK_GATE_DISABLE	(1<<10)
 
 /* Fuse readout registers for GT */
-#define CHV_FUSE_GT			(VLV_DISPLAY_BASE + 0x2168)
+#define CHV_FUSE_GT			_MMIO(VLV_DISPLAY_BASE + 0x2168)
 #define   CHV_FGT_DISABLE_SS0		(1 << 10)
 #define   CHV_FGT_DISABLE_SS1		(1 << 11)
 #define   CHV_FGT_EU_DIS_SS0_R0_SHIFT	16
@@ -1893,7 +1953,7 @@
 #define   CHV_FGT_EU_DIS_SS1_R1_SHIFT	28
 #define   CHV_FGT_EU_DIS_SS1_R1_MASK	(0xf << CHV_FGT_EU_DIS_SS1_R1_SHIFT)
 
-#define GEN8_FUSE2			0x9120
+#define GEN8_FUSE2			_MMIO(0x9120)
 #define   GEN8_F2_SS_DIS_SHIFT		21
 #define   GEN8_F2_SS_DIS_MASK		(0x7 << GEN8_F2_SS_DIS_SHIFT)
 #define   GEN8_F2_S_ENA_SHIFT		25
@@ -1902,22 +1962,22 @@
 #define   GEN9_F2_SS_DIS_SHIFT		20
 #define   GEN9_F2_SS_DIS_MASK		(0xf << GEN9_F2_SS_DIS_SHIFT)
 
-#define GEN8_EU_DISABLE0		0x9134
+#define GEN8_EU_DISABLE0		_MMIO(0x9134)
 #define   GEN8_EU_DIS0_S0_MASK		0xffffff
 #define   GEN8_EU_DIS0_S1_SHIFT		24
 #define   GEN8_EU_DIS0_S1_MASK		(0xff << GEN8_EU_DIS0_S1_SHIFT)
 
-#define GEN8_EU_DISABLE1		0x9138
+#define GEN8_EU_DISABLE1		_MMIO(0x9138)
 #define   GEN8_EU_DIS1_S1_MASK		0xffff
 #define   GEN8_EU_DIS1_S2_SHIFT		16
 #define   GEN8_EU_DIS1_S2_MASK		(0xffff << GEN8_EU_DIS1_S2_SHIFT)
 
-#define GEN8_EU_DISABLE2		0x913c
+#define GEN8_EU_DISABLE2		_MMIO(0x913c)
 #define   GEN8_EU_DIS2_S2_MASK		0xff
 
-#define GEN9_EU_DISABLE(slice)		(0x9134 + (slice)*0x4)
+#define GEN9_EU_DISABLE(slice)		_MMIO(0x9134 + (slice)*0x4)
 
-#define GEN6_BSD_SLEEP_PSMI_CONTROL	0x12050
+#define GEN6_BSD_SLEEP_PSMI_CONTROL	_MMIO(0x12050)
 #define   GEN6_BSD_SLEEP_MSG_DISABLE	(1 << 0)
 #define   GEN6_BSD_SLEEP_FLUSH_DISABLE	(1 << 2)
 #define   GEN6_BSD_SLEEP_INDICATOR	(1 << 3)
@@ -1995,9 +2055,9 @@
 #define I915_ASLE_INTERRUPT				(1<<0)
 #define I915_BSD_USER_INTERRUPT				(1<<25)
 
-#define GEN6_BSD_RNCID			0x12198
+#define GEN6_BSD_RNCID			_MMIO(0x12198)
 
-#define GEN7_FF_THREAD_MODE		0x20a0
+#define GEN7_FF_THREAD_MODE		_MMIO(0x20a0)
 #define   GEN7_FF_SCHED_MASK		0x0077070
 #define   GEN8_FF_DS_REF_CNT_FFME	(1 << 19)
 #define   GEN7_FF_TS_SCHED_HS1		(0x5<<16)
@@ -2018,9 +2078,9 @@
  * Framebuffer compression (915+ only)
  */
 
-#define FBC_CFB_BASE		0x03200 /* 4k page aligned */
-#define FBC_LL_BASE		0x03204 /* 4k page aligned */
-#define FBC_CONTROL		0x03208
+#define FBC_CFB_BASE		_MMIO(0x3200) /* 4k page aligned */
+#define FBC_LL_BASE		_MMIO(0x3204) /* 4k page aligned */
+#define FBC_CONTROL		_MMIO(0x3208)
 #define   FBC_CTL_EN		(1<<31)
 #define   FBC_CTL_PERIODIC	(1<<30)
 #define   FBC_CTL_INTERVAL_SHIFT (16)
@@ -2028,14 +2088,14 @@
 #define   FBC_CTL_C3_IDLE	(1<<13)
 #define   FBC_CTL_STRIDE_SHIFT	(5)
 #define   FBC_CTL_FENCENO_SHIFT	(0)
-#define FBC_COMMAND		0x0320c
+#define FBC_COMMAND		_MMIO(0x320c)
 #define   FBC_CMD_COMPRESS	(1<<0)
-#define FBC_STATUS		0x03210
+#define FBC_STATUS		_MMIO(0x3210)
 #define   FBC_STAT_COMPRESSING	(1<<31)
 #define   FBC_STAT_COMPRESSED	(1<<30)
 #define   FBC_STAT_MODIFIED	(1<<29)
 #define   FBC_STAT_CURRENT_LINE_SHIFT	(0)
-#define FBC_CONTROL2		0x03214
+#define FBC_CONTROL2		_MMIO(0x3214)
 #define   FBC_CTL_FENCE_DBL	(0<<4)
 #define   FBC_CTL_IDLE_IMM	(0<<2)
 #define   FBC_CTL_IDLE_FULL	(1<<2)
@@ -2043,17 +2103,17 @@
 #define   FBC_CTL_IDLE_DEBUG	(3<<2)
 #define   FBC_CTL_CPU_FENCE	(1<<1)
 #define   FBC_CTL_PLANE(plane)	((plane)<<0)
-#define FBC_FENCE_OFF		0x03218 /* BSpec typo has 321Bh */
-#define FBC_TAG(i)		(0x03300 + (i) * 4)
+#define FBC_FENCE_OFF		_MMIO(0x3218) /* BSpec typo has 321Bh */
+#define FBC_TAG(i)		_MMIO(0x3300 + (i) * 4)
 
-#define FBC_STATUS2		0x43214
+#define FBC_STATUS2		_MMIO(0x43214)
 #define  FBC_COMPRESSION_MASK	0x7ff
 
 #define FBC_LL_SIZE		(1536)
 
 /* Framebuffer compression for GM45+ */
-#define DPFC_CB_BASE		0x3200
-#define DPFC_CONTROL		0x3208
+#define DPFC_CB_BASE		_MMIO(0x3200)
+#define DPFC_CONTROL		_MMIO(0x3208)
 #define   DPFC_CTL_EN		(1<<31)
 #define   DPFC_CTL_PLANE(plane)	((plane)<<30)
 #define   IVB_DPFC_CTL_PLANE(plane)	((plane)<<29)
@@ -2064,37 +2124,37 @@
 #define   DPFC_CTL_LIMIT_1X	(0<<6)
 #define   DPFC_CTL_LIMIT_2X	(1<<6)
 #define   DPFC_CTL_LIMIT_4X	(2<<6)
-#define DPFC_RECOMP_CTL		0x320c
+#define DPFC_RECOMP_CTL		_MMIO(0x320c)
 #define   DPFC_RECOMP_STALL_EN	(1<<27)
 #define   DPFC_RECOMP_STALL_WM_SHIFT (16)
 #define   DPFC_RECOMP_STALL_WM_MASK (0x07ff0000)
 #define   DPFC_RECOMP_TIMER_COUNT_SHIFT (0)
 #define   DPFC_RECOMP_TIMER_COUNT_MASK (0x0000003f)
-#define DPFC_STATUS		0x3210
+#define DPFC_STATUS		_MMIO(0x3210)
 #define   DPFC_INVAL_SEG_SHIFT  (16)
 #define   DPFC_INVAL_SEG_MASK	(0x07ff0000)
 #define   DPFC_COMP_SEG_SHIFT	(0)
 #define   DPFC_COMP_SEG_MASK	(0x000003ff)
-#define DPFC_STATUS2		0x3214
-#define DPFC_FENCE_YOFF		0x3218
-#define DPFC_CHICKEN		0x3224
+#define DPFC_STATUS2		_MMIO(0x3214)
+#define DPFC_FENCE_YOFF		_MMIO(0x3218)
+#define DPFC_CHICKEN		_MMIO(0x3224)
 #define   DPFC_HT_MODIFY	(1<<31)
 
 /* Framebuffer compression for Ironlake */
-#define ILK_DPFC_CB_BASE	0x43200
-#define ILK_DPFC_CONTROL	0x43208
+#define ILK_DPFC_CB_BASE	_MMIO(0x43200)
+#define ILK_DPFC_CONTROL	_MMIO(0x43208)
 #define   FBC_CTL_FALSE_COLOR	(1<<10)
 /* The bit 28-8 is reserved */
 #define   DPFC_RESERVED		(0x1FFFFF00)
-#define ILK_DPFC_RECOMP_CTL	0x4320c
-#define ILK_DPFC_STATUS		0x43210
-#define ILK_DPFC_FENCE_YOFF	0x43218
-#define ILK_DPFC_CHICKEN	0x43224
-#define ILK_FBC_RT_BASE		0x2128
+#define ILK_DPFC_RECOMP_CTL	_MMIO(0x4320c)
+#define ILK_DPFC_STATUS		_MMIO(0x43210)
+#define ILK_DPFC_FENCE_YOFF	_MMIO(0x43218)
+#define ILK_DPFC_CHICKEN	_MMIO(0x43224)
+#define ILK_FBC_RT_BASE		_MMIO(0x2128)
 #define   ILK_FBC_RT_VALID	(1<<0)
 #define   SNB_FBC_FRONT_BUFFER	(1<<1)
 
-#define ILK_DISPLAY_CHICKEN1	0x42000
+#define ILK_DISPLAY_CHICKEN1	_MMIO(0x42000)
 #define   ILK_FBCQ_DIS		(1<<22)
 #define	  ILK_PABSTRETCH_DIS	(1<<21)
 
@@ -2104,31 +2164,31 @@
  *
  * The following two registers are of type GTTMMADR
  */
-#define SNB_DPFC_CTL_SA		0x100100
+#define SNB_DPFC_CTL_SA		_MMIO(0x100100)
 #define   SNB_CPU_FENCE_ENABLE	(1<<29)
-#define DPFC_CPU_FENCE_OFFSET	0x100104
+#define DPFC_CPU_FENCE_OFFSET	_MMIO(0x100104)
 
 /* Framebuffer compression for Ivybridge */
-#define IVB_FBC_RT_BASE			0x7020
+#define IVB_FBC_RT_BASE			_MMIO(0x7020)
 
-#define IPS_CTL		0x43408
+#define IPS_CTL		_MMIO(0x43408)
 #define   IPS_ENABLE	(1 << 31)
 
-#define MSG_FBC_REND_STATE	0x50380
+#define MSG_FBC_REND_STATE	_MMIO(0x50380)
 #define   FBC_REND_NUKE		(1<<2)
 #define   FBC_REND_CACHE_CLEAN	(1<<1)
 
 /*
  * GPIO regs
  */
-#define GPIOA			0x5010
-#define GPIOB			0x5014
-#define GPIOC			0x5018
-#define GPIOD			0x501c
-#define GPIOE			0x5020
-#define GPIOF			0x5024
-#define GPIOG			0x5028
-#define GPIOH			0x502c
+#define GPIOA			_MMIO(0x5010)
+#define GPIOB			_MMIO(0x5014)
+#define GPIOC			_MMIO(0x5018)
+#define GPIOD			_MMIO(0x501c)
+#define GPIOE			_MMIO(0x5020)
+#define GPIOF			_MMIO(0x5024)
+#define GPIOG			_MMIO(0x5028)
+#define GPIOH			_MMIO(0x502c)
 # define GPIO_CLOCK_DIR_MASK		(1 << 0)
 # define GPIO_CLOCK_DIR_IN		(0 << 1)
 # define GPIO_CLOCK_DIR_OUT		(1 << 1)
@@ -2144,7 +2204,7 @@
 # define GPIO_DATA_VAL_IN		(1 << 12)
 # define GPIO_DATA_PULLUP_DISABLE	(1 << 13)
 
-#define GMBUS0			(dev_priv->gpio_mmio_base + 0x5100) /* clock/port select */
+#define GMBUS0			_MMIO(dev_priv->gpio_mmio_base + 0x5100) /* clock/port select */
 #define   GMBUS_RATE_100KHZ	(0<<8)
 #define   GMBUS_RATE_50KHZ	(1<<8)
 #define   GMBUS_RATE_400KHZ	(2<<8) /* reserved on Pineview */
@@ -2163,7 +2223,7 @@
 #define   GMBUS_PIN_2_BXT	2
 #define   GMBUS_PIN_3_BXT	3
 #define   GMBUS_NUM_PINS	7 /* including 0 */
-#define GMBUS1			(dev_priv->gpio_mmio_base + 0x5104) /* command/status */
+#define GMBUS1			_MMIO(dev_priv->gpio_mmio_base + 0x5104) /* command/status */
 #define   GMBUS_SW_CLR_INT	(1<<31)
 #define   GMBUS_SW_RDY		(1<<30)
 #define   GMBUS_ENT		(1<<29) /* enable timeout */
@@ -2177,7 +2237,7 @@
 #define   GMBUS_SLAVE_ADDR_SHIFT 1
 #define   GMBUS_SLAVE_READ	(1<<0)
 #define   GMBUS_SLAVE_WRITE	(0<<0)
-#define GMBUS2			(dev_priv->gpio_mmio_base + 0x5108) /* status */
+#define GMBUS2			_MMIO(dev_priv->gpio_mmio_base + 0x5108) /* status */
 #define   GMBUS_INUSE		(1<<15)
 #define   GMBUS_HW_WAIT_PHASE	(1<<14)
 #define   GMBUS_STALL_TIMEOUT	(1<<13)
@@ -2185,14 +2245,14 @@
 #define   GMBUS_HW_RDY		(1<<11)
 #define   GMBUS_SATOER		(1<<10)
 #define   GMBUS_ACTIVE		(1<<9)
-#define GMBUS3			(dev_priv->gpio_mmio_base + 0x510c) /* data buffer bytes 3-0 */
-#define GMBUS4			(dev_priv->gpio_mmio_base + 0x5110) /* interrupt mask (Pineview+) */
+#define GMBUS3			_MMIO(dev_priv->gpio_mmio_base + 0x510c) /* data buffer bytes 3-0 */
+#define GMBUS4			_MMIO(dev_priv->gpio_mmio_base + 0x5110) /* interrupt mask (Pineview+) */
 #define   GMBUS_SLAVE_TIMEOUT_EN (1<<4)
 #define   GMBUS_NAK_EN		(1<<3)
 #define   GMBUS_IDLE_EN		(1<<2)
 #define   GMBUS_HW_WAIT_EN	(1<<1)
 #define   GMBUS_HW_RDY_EN	(1<<0)
-#define GMBUS5			(dev_priv->gpio_mmio_base + 0x5120) /* byte index */
+#define GMBUS5			_MMIO(dev_priv->gpio_mmio_base + 0x5120) /* byte index */
 #define   GMBUS_2BYTE_INDEX_EN	(1<<31)
 
 /*
@@ -2201,11 +2261,11 @@
 #define _DPLL_A (dev_priv->info.display_mmio_offset + 0x6014)
 #define _DPLL_B (dev_priv->info.display_mmio_offset + 0x6018)
 #define _CHV_DPLL_C (dev_priv->info.display_mmio_offset + 0x6030)
-#define DPLL(pipe) _PIPE3((pipe), _DPLL_A, _DPLL_B, _CHV_DPLL_C)
+#define DPLL(pipe) _MMIO_PIPE3((pipe), _DPLL_A, _DPLL_B, _CHV_DPLL_C)
 
-#define VGA0	0x6000
-#define VGA1	0x6004
-#define VGA_PD	0x6010
+#define VGA0	_MMIO(0x6000)
+#define VGA1	_MMIO(0x6004)
+#define VGA_PD	_MMIO(0x6010)
 #define   VGA0_PD_P2_DIV_4	(1 << 7)
 #define   VGA0_PD_P1_DIV_2	(1 << 5)
 #define   VGA0_PD_P1_SHIFT	0
@@ -2241,9 +2301,9 @@
 #define   DPLL_FPA01_P1_POST_DIV_MASK_I830	0x001f0000
 
 /* Additional CHV pll/phy registers */
-#define DPIO_PHY_STATUS			(VLV_DISPLAY_BASE + 0x6240)
+#define DPIO_PHY_STATUS			_MMIO(VLV_DISPLAY_BASE + 0x6240)
 #define   DPLL_PORTD_READY_MASK		(0xf)
-#define DISPLAY_PHY_CONTROL (VLV_DISPLAY_BASE + 0x60100)
+#define DISPLAY_PHY_CONTROL _MMIO(VLV_DISPLAY_BASE + 0x60100)
 #define   PHY_CH_POWER_DOWN_OVRD_EN(phy, ch)	(1 << (2*(phy)+(ch)+27))
 #define   PHY_LDO_DELAY_0NS			0x0
 #define   PHY_LDO_DELAY_200NS			0x1
@@ -2254,7 +2314,7 @@
 #define   PHY_CH_DEEP_PSR			0x7
 #define   PHY_CH_POWER_MODE(mode, phy, ch)	((mode) << (6*(phy)+3*(ch)+2))
 #define   PHY_COM_LANE_RESET_DEASSERT(phy)	(1 << (phy))
-#define DISPLAY_PHY_STATUS (VLV_DISPLAY_BASE + 0x60104)
+#define DISPLAY_PHY_STATUS _MMIO(VLV_DISPLAY_BASE + 0x60104)
 #define   PHY_POWERGOOD(phy)	(((phy) == DPIO_PHY0) ? (1<<31) : (1<<30))
 #define   PHY_STATUS_CMN_LDO(phy, ch)                   (1 << (6-(6*(phy)+3*(ch))))
 #define   PHY_STATUS_SPLINE_LDO(phy, ch, spline)        (1 << (8-(6*(phy)+3*(ch)+(spline))))
@@ -2300,7 +2360,7 @@
 #define _DPLL_A_MD (dev_priv->info.display_mmio_offset + 0x601c)
 #define _DPLL_B_MD (dev_priv->info.display_mmio_offset + 0x6020)
 #define _CHV_DPLL_C_MD (dev_priv->info.display_mmio_offset + 0x603c)
-#define DPLL_MD(pipe) _PIPE3((pipe), _DPLL_A_MD, _DPLL_B_MD, _CHV_DPLL_C_MD)
+#define DPLL_MD(pipe) _MMIO_PIPE3((pipe), _DPLL_A_MD, _DPLL_B_MD, _CHV_DPLL_C_MD)
 
 /*
  * UDI pixel divider, controlling how many pixels are stuffed into a packet.
@@ -2339,12 +2399,12 @@
 #define   DPLL_MD_VGA_UDI_MULTIPLIER_MASK	0x0000003f
 #define   DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT	0
 
-#define _FPA0	0x06040
-#define _FPA1	0x06044
-#define _FPB0	0x06048
-#define _FPB1	0x0604c
-#define FP0(pipe) _PIPE(pipe, _FPA0, _FPB0)
-#define FP1(pipe) _PIPE(pipe, _FPA1, _FPB1)
+#define _FPA0	0x6040
+#define _FPA1	0x6044
+#define _FPB0	0x6048
+#define _FPB1	0x604c
+#define FP0(pipe) _MMIO_PIPE(pipe, _FPA0, _FPB0)
+#define FP1(pipe) _MMIO_PIPE(pipe, _FPA1, _FPB1)
 #define   FP_N_DIV_MASK		0x003f0000
 #define   FP_N_PINEVIEW_DIV_MASK	0x00ff0000
 #define   FP_N_DIV_SHIFT		16
@@ -2353,7 +2413,7 @@
 #define   FP_M2_DIV_MASK	0x0000003f
 #define   FP_M2_PINEVIEW_DIV_MASK	0x000000ff
 #define   FP_M2_DIV_SHIFT		 0
-#define DPLL_TEST	0x606c
+#define DPLL_TEST	_MMIO(0x606c)
 #define   DPLLB_TEST_SDVO_DIV_1		(0 << 22)
 #define   DPLLB_TEST_SDVO_DIV_2		(1 << 22)
 #define   DPLLB_TEST_SDVO_DIV_4		(2 << 22)
@@ -2364,12 +2424,12 @@
 #define   DPLLA_TEST_N_BYPASS		(1 << 3)
 #define   DPLLA_TEST_M_BYPASS		(1 << 2)
 #define   DPLLA_INPUT_BUFFER_ENABLE	(1 << 0)
-#define D_STATE		0x6104
+#define D_STATE		_MMIO(0x6104)
 #define  DSTATE_GFX_RESET_I830			(1<<6)
 #define  DSTATE_PLL_D3_OFF			(1<<3)
 #define  DSTATE_GFX_CLOCK_GATING		(1<<1)
 #define  DSTATE_DOT_CLOCK_GATING		(1<<0)
-#define DSPCLK_GATE_D	(dev_priv->info.display_mmio_offset + 0x6200)
+#define DSPCLK_GATE_D	_MMIO(dev_priv->info.display_mmio_offset + 0x6200)
 # define DPUNIT_B_CLOCK_GATE_DISABLE		(1 << 30) /* 965 */
 # define VSUNIT_CLOCK_GATE_DISABLE		(1 << 29) /* 965 */
 # define VRHUNIT_CLOCK_GATE_DISABLE		(1 << 28) /* 965 */
@@ -2408,7 +2468,7 @@
 # define ZVUNIT_CLOCK_GATE_DISABLE		(1 << 0) /* 830 */
 # define OVLUNIT_CLOCK_GATE_DISABLE		(1 << 0) /* 845,865 */
 
-#define RENCLK_GATE_D1		0x6204
+#define RENCLK_GATE_D1		_MMIO(0x6204)
 # define BLITTER_CLOCK_GATE_DISABLE		(1 << 13) /* 945GM only */
 # define MPEG_CLOCK_GATE_DISABLE		(1 << 12) /* 945GM only */
 # define PC_FE_CLOCK_GATE_DISABLE		(1 << 11)
@@ -2472,35 +2532,35 @@
 # define I965_FT_CLOCK_GATE_DISABLE		(1 << 1)
 # define I965_DM_CLOCK_GATE_DISABLE		(1 << 0)
 
-#define RENCLK_GATE_D2		0x6208
+#define RENCLK_GATE_D2		_MMIO(0x6208)
 #define VF_UNIT_CLOCK_GATE_DISABLE		(1 << 9)
 #define GS_UNIT_CLOCK_GATE_DISABLE		(1 << 7)
 #define CL_UNIT_CLOCK_GATE_DISABLE		(1 << 6)
 
-#define VDECCLK_GATE_D		0x620C		/* g4x only */
+#define VDECCLK_GATE_D		_MMIO(0x620C)		/* g4x only */
 #define  VCP_UNIT_CLOCK_GATE_DISABLE		(1 << 4)
 
-#define RAMCLK_GATE_D		0x6210		/* CRL only */
-#define DEUC			0x6214          /* CRL only */
+#define RAMCLK_GATE_D		_MMIO(0x6210)		/* CRL only */
+#define DEUC			_MMIO(0x6214)          /* CRL only */
 
-#define FW_BLC_SELF_VLV		(VLV_DISPLAY_BASE + 0x6500)
+#define FW_BLC_SELF_VLV		_MMIO(VLV_DISPLAY_BASE + 0x6500)
 #define  FW_CSPWRDWNEN		(1<<15)
 
-#define MI_ARB_VLV		(VLV_DISPLAY_BASE + 0x6504)
+#define MI_ARB_VLV		_MMIO(VLV_DISPLAY_BASE + 0x6504)
 
-#define CZCLK_CDCLK_FREQ_RATIO	(VLV_DISPLAY_BASE + 0x6508)
+#define CZCLK_CDCLK_FREQ_RATIO	_MMIO(VLV_DISPLAY_BASE + 0x6508)
 #define   CDCLK_FREQ_SHIFT	4
 #define   CDCLK_FREQ_MASK	(0x1f << CDCLK_FREQ_SHIFT)
 #define   CZCLK_FREQ_MASK	0xf
 
-#define GCI_CONTROL		(VLV_DISPLAY_BASE + 0x650C)
+#define GCI_CONTROL		_MMIO(VLV_DISPLAY_BASE + 0x650C)
 #define   PFI_CREDIT_63		(9 << 28)		/* chv only */
 #define   PFI_CREDIT_31		(8 << 28)		/* chv only */
 #define   PFI_CREDIT(x)		(((x) - 8) << 28)	/* 8-15 */
 #define   PFI_CREDIT_RESEND	(1 << 27)
 #define   VGA_FAST_MODE_DISABLE	(1 << 14)
 
-#define GMBUSFREQ_VLV		(VLV_DISPLAY_BASE + 0x6510)
+#define GMBUSFREQ_VLV		_MMIO(VLV_DISPLAY_BASE + 0x6510)
 
 /*
  * Palette regs
@@ -2508,8 +2568,8 @@
 #define PALETTE_A_OFFSET 0xa000
 #define PALETTE_B_OFFSET 0xa800
 #define CHV_PALETTE_C_OFFSET 0xc000
-#define PALETTE(pipe, i) (dev_priv->info.palette_offsets[pipe] + \
-			  dev_priv->info.display_mmio_offset + (i) * 4)
+#define PALETTE(pipe, i) _MMIO(dev_priv->info.palette_offsets[pipe] +	\
+			      dev_priv->info.display_mmio_offset + (i) * 4)
 
 /* MCH MMIO space */
 
@@ -2527,37 +2587,37 @@
 
 #define MCHBAR_MIRROR_BASE_SNB	0x140000
 
-#define CTG_STOLEN_RESERVED		(MCHBAR_MIRROR_BASE + 0x34)
-#define ELK_STOLEN_RESERVED		(MCHBAR_MIRROR_BASE + 0x48)
+#define CTG_STOLEN_RESERVED		_MMIO(MCHBAR_MIRROR_BASE + 0x34)
+#define ELK_STOLEN_RESERVED		_MMIO(MCHBAR_MIRROR_BASE + 0x48)
 #define G4X_STOLEN_RESERVED_ADDR1_MASK	(0xFFFF << 16)
 #define G4X_STOLEN_RESERVED_ADDR2_MASK	(0xFFF << 4)
 
 /* Memory controller frequency in MCHBAR for Haswell (possible SNB+) */
-#define DCLK (MCHBAR_MIRROR_BASE_SNB + 0x5e04)
+#define DCLK _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5e04)
 
 /* 915-945 and GM965 MCH register controlling DRAM channel access */
-#define DCC			0x10200
+#define DCC			_MMIO(MCHBAR_MIRROR_BASE + 0x200)
 #define DCC_ADDRESSING_MODE_SINGLE_CHANNEL		(0 << 0)
 #define DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC	(1 << 0)
 #define DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED	(2 << 0)
 #define DCC_ADDRESSING_MODE_MASK			(3 << 0)
 #define DCC_CHANNEL_XOR_DISABLE				(1 << 10)
 #define DCC_CHANNEL_XOR_BIT_17				(1 << 9)
-#define DCC2			0x10204
+#define DCC2			_MMIO(MCHBAR_MIRROR_BASE + 0x204)
 #define DCC2_MODIFIED_ENHANCED_DISABLE			(1 << 20)
 
 /* Pineview MCH register contains DDR3 setting */
-#define CSHRDDR3CTL            0x101a8
+#define CSHRDDR3CTL            _MMIO(MCHBAR_MIRROR_BASE + 0x1a8)
 #define CSHRDDR3CTL_DDR3       (1 << 2)
 
 /* 965 MCH register controlling DRAM channel configuration */
-#define C0DRB3			0x10206
-#define C1DRB3			0x10606
+#define C0DRB3			_MMIO(MCHBAR_MIRROR_BASE + 0x206)
+#define C1DRB3			_MMIO(MCHBAR_MIRROR_BASE + 0x606)
 
 /* snb MCH registers for reading the DRAM channel configuration */
-#define MAD_DIMM_C0			(MCHBAR_MIRROR_BASE_SNB + 0x5004)
-#define MAD_DIMM_C1			(MCHBAR_MIRROR_BASE_SNB + 0x5008)
-#define MAD_DIMM_C2			(MCHBAR_MIRROR_BASE_SNB + 0x500C)
+#define MAD_DIMM_C0			_MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5004)
+#define MAD_DIMM_C1			_MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5008)
+#define MAD_DIMM_C2			_MMIO(MCHBAR_MIRROR_BASE_SNB + 0x500C)
 #define   MAD_DIMM_ECC_MASK		(0x3 << 24)
 #define   MAD_DIMM_ECC_OFF		(0x0 << 24)
 #define   MAD_DIMM_ECC_IO_ON_LOGIC_OFF	(0x1 << 24)
@@ -2577,14 +2637,14 @@
 #define   MAD_DIMM_A_SIZE_MASK		(0xff << MAD_DIMM_A_SIZE_SHIFT)
 
 /* snb MCH registers for priority tuning */
-#define MCH_SSKPD			(MCHBAR_MIRROR_BASE_SNB + 0x5d10)
+#define MCH_SSKPD			_MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5d10)
 #define   MCH_SSKPD_WM0_MASK		0x3f
 #define   MCH_SSKPD_WM0_VAL		0xc
 
-#define MCH_SECP_NRG_STTS		(MCHBAR_MIRROR_BASE_SNB + 0x592c)
+#define MCH_SECP_NRG_STTS		_MMIO(MCHBAR_MIRROR_BASE_SNB + 0x592c)
 
 /* Clocking configuration register */
-#define CLKCFG			0x10c00
+#define CLKCFG			_MMIO(MCHBAR_MIRROR_BASE + 0xc00)
 #define CLKCFG_FSB_400					(5 << 0)	/* hrawclk 100 */
 #define CLKCFG_FSB_533					(1 << 0)	/* hrawclk 133 */
 #define CLKCFG_FSB_667					(3 << 0)	/* hrawclk 166 */
@@ -2600,26 +2660,26 @@
 #define CLKCFG_MEM_800					(3 << 4)
 #define CLKCFG_MEM_MASK					(7 << 4)
 
-#define HPLLVCO                 (MCHBAR_MIRROR_BASE + 0xc38)
-#define HPLLVCO_MOBILE          (MCHBAR_MIRROR_BASE + 0xc0f)
+#define HPLLVCO                 _MMIO(MCHBAR_MIRROR_BASE + 0xc38)
+#define HPLLVCO_MOBILE          _MMIO(MCHBAR_MIRROR_BASE + 0xc0f)
 
-#define TSC1			0x11001
+#define TSC1			_MMIO(0x11001)
 #define   TSE			(1<<0)
-#define TR1			0x11006
-#define TSFS			0x11020
+#define TR1			_MMIO(0x11006)
+#define TSFS			_MMIO(0x11020)
 #define   TSFS_SLOPE_MASK	0x0000ff00
 #define   TSFS_SLOPE_SHIFT	8
 #define   TSFS_INTR_MASK	0x000000ff
 
-#define CRSTANDVID		0x11100
-#define PXVFREQ(i)		(0x11110 + (i) * 4) /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */
+#define CRSTANDVID		_MMIO(0x11100)
+#define PXVFREQ(fstart)		_MMIO(0x11110 + (fstart) * 4)  /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */
 #define   PXVFREQ_PX_MASK	0x7f000000
 #define   PXVFREQ_PX_SHIFT	24
-#define VIDFREQ_BASE		0x11110
-#define VIDFREQ1		0x11110 /* VIDFREQ1-4 (0x1111c) (Cantiga) */
-#define VIDFREQ2		0x11114
-#define VIDFREQ3		0x11118
-#define VIDFREQ4		0x1111c
+#define VIDFREQ_BASE		_MMIO(0x11110)
+#define VIDFREQ1		_MMIO(0x11110) /* VIDFREQ1-4 (0x1111c) (Cantiga) */
+#define VIDFREQ2		_MMIO(0x11114)
+#define VIDFREQ3		_MMIO(0x11118)
+#define VIDFREQ4		_MMIO(0x1111c)
 #define   VIDFREQ_P0_MASK	0x1f000000
 #define   VIDFREQ_P0_SHIFT	24
 #define   VIDFREQ_P0_CSCLK_MASK	0x00f00000
@@ -2631,8 +2691,8 @@
 #define   VIDFREQ_P1_CSCLK_MASK	0x000000f0
 #define   VIDFREQ_P1_CSCLK_SHIFT 4
 #define   VIDFREQ_P1_CRCLK_MASK	0x0000000f
-#define INTTOEXT_BASE_ILK	0x11300
-#define INTTOEXT_BASE		0x11120 /* INTTOEXT1-8 (0x1113c) */
+#define INTTOEXT_BASE_ILK	_MMIO(0x11300)
+#define INTTOEXT_BASE		_MMIO(0x11120) /* INTTOEXT1-8 (0x1113c) */
 #define   INTTOEXT_MAP3_SHIFT	24
 #define   INTTOEXT_MAP3_MASK	(0x1f << INTTOEXT_MAP3_SHIFT)
 #define   INTTOEXT_MAP2_SHIFT	16
@@ -2641,7 +2701,7 @@
 #define   INTTOEXT_MAP1_MASK	(0x1f << INTTOEXT_MAP1_SHIFT)
 #define   INTTOEXT_MAP0_SHIFT	0
 #define   INTTOEXT_MAP0_MASK	(0x1f << INTTOEXT_MAP0_SHIFT)
-#define MEMSWCTL		0x11170 /* Ironlake only */
+#define MEMSWCTL		_MMIO(0x11170) /* Ironlake only */
 #define   MEMCTL_CMD_MASK	0xe000
 #define   MEMCTL_CMD_SHIFT	13
 #define   MEMCTL_CMD_RCLK_OFF	0
@@ -2656,8 +2716,8 @@
 #define   MEMCTL_FREQ_SHIFT	8
 #define   MEMCTL_SFCAVM		(1<<7)
 #define   MEMCTL_TGT_VID_MASK	0x007f
-#define MEMIHYST		0x1117c
-#define MEMINTREN		0x11180 /* 16 bits */
+#define MEMIHYST		_MMIO(0x1117c)
+#define MEMINTREN		_MMIO(0x11180) /* 16 bits */
 #define   MEMINT_RSEXIT_EN	(1<<8)
 #define   MEMINT_CX_SUPR_EN	(1<<7)
 #define   MEMINT_CONT_BUSY_EN	(1<<6)
@@ -2667,7 +2727,7 @@
 #define   MEMINT_UP_EVAL_EN	(1<<2)
 #define   MEMINT_DOWN_EVAL_EN	(1<<1)
 #define   MEMINT_SW_CMD_EN	(1<<0)
-#define MEMINTRSTR		0x11182 /* 16 bits */
+#define MEMINTRSTR		_MMIO(0x11182) /* 16 bits */
 #define   MEM_RSEXIT_MASK	0xc000
 #define   MEM_RSEXIT_SHIFT	14
 #define   MEM_CONT_BUSY_MASK	0x3000
@@ -2687,7 +2747,7 @@
 #define   MEM_INT_STEER_CMR	1
 #define   MEM_INT_STEER_SMI	2
 #define   MEM_INT_STEER_SCI	3
-#define MEMINTRSTS		0x11184
+#define MEMINTRSTS		_MMIO(0x11184)
 #define   MEMINT_RSEXIT		(1<<7)
 #define   MEMINT_CONT_BUSY	(1<<6)
 #define   MEMINT_AVG_BUSY	(1<<5)
@@ -2696,7 +2756,7 @@
 #define   MEMINT_UP_EVAL	(1<<2)
 #define   MEMINT_DOWN_EVAL	(1<<1)
 #define   MEMINT_SW_CMD		(1<<0)
-#define MEMMODECTL		0x11190
+#define MEMMODECTL		_MMIO(0x11190)
 #define   MEMMODE_BOOST_EN	(1<<31)
 #define   MEMMODE_BOOST_FREQ_MASK 0x0f000000 /* jitter for boost, 0-15 */
 #define   MEMMODE_BOOST_FREQ_SHIFT 24
@@ -2713,8 +2773,8 @@
 #define   MEMMODE_FMAX_MASK	0x000000f0 /* max jitter, 0-15 */
 #define   MEMMODE_FMAX_SHIFT	4
 #define   MEMMODE_FMIN_MASK	0x0000000f /* min jitter, 0-15 */
-#define RCBMAXAVG		0x1119c
-#define MEMSWCTL2		0x1119e /* Cantiga only */
+#define RCBMAXAVG		_MMIO(0x1119c)
+#define MEMSWCTL2		_MMIO(0x1119e) /* Cantiga only */
 #define   SWMEMCMD_RENDER_OFF	(0 << 13)
 #define   SWMEMCMD_RENDER_ON	(1 << 13)
 #define   SWMEMCMD_SWFREQ	(2 << 13)
@@ -2726,11 +2786,11 @@
 #define   SWFREQ_MASK		0x0380 /* P0-7 */
 #define   SWFREQ_SHIFT		7
 #define   TARVID_MASK		0x001f
-#define MEMSTAT_CTG		0x111a0
-#define RCBMINAVG		0x111a0
-#define RCUPEI			0x111b0
-#define RCDNEI			0x111b4
-#define RSTDBYCTL		0x111b8
+#define MEMSTAT_CTG		_MMIO(0x111a0)
+#define RCBMINAVG		_MMIO(0x111a0)
+#define RCUPEI			_MMIO(0x111b0)
+#define RCDNEI			_MMIO(0x111b4)
+#define RSTDBYCTL		_MMIO(0x111b8)
 #define   RS1EN			(1<<31)
 #define   RS2EN			(1<<30)
 #define   RS3EN			(1<<29)
@@ -2774,10 +2834,10 @@
 #define   RS_CSTATE_C367_RS2	(3<<4)
 #define   REDSAVES		(1<<3) /* no context save if was idle during rs0 */
 #define   REDRESTORES		(1<<2) /* no restore if was idle during rs0 */
-#define VIDCTL			0x111c0
-#define VIDSTS			0x111c8
-#define VIDSTART		0x111cc /* 8 bits */
-#define MEMSTAT_ILK			0x111f8
+#define VIDCTL			_MMIO(0x111c0)
+#define VIDSTS			_MMIO(0x111c8)
+#define VIDSTART		_MMIO(0x111cc) /* 8 bits */
+#define MEMSTAT_ILK		_MMIO(0x111f8)
 #define   MEMSTAT_VID_MASK	0x7f00
 #define   MEMSTAT_VID_SHIFT	8
 #define   MEMSTAT_PSTATE_MASK	0x00f8
@@ -2788,55 +2848,55 @@
 #define   MEMSTAT_SRC_CTL_TRB	1
 #define   MEMSTAT_SRC_CTL_THM	2
 #define   MEMSTAT_SRC_CTL_STDBY 3
-#define RCPREVBSYTUPAVG		0x113b8
-#define RCPREVBSYTDNAVG		0x113bc
-#define PMMISC			0x11214
+#define RCPREVBSYTUPAVG		_MMIO(0x113b8)
+#define RCPREVBSYTDNAVG		_MMIO(0x113bc)
+#define PMMISC			_MMIO(0x11214)
 #define   MCPPCE_EN		(1<<0) /* enable PM_MSG from PCH->MPC */
-#define SDEW			0x1124c
-#define CSIEW0			0x11250
-#define CSIEW1			0x11254
-#define CSIEW2			0x11258
-#define PEW(i)			(0x1125c + (i) * 4) /* 5 registers */
-#define DEW(i)			(0x11270 + (i) * 4) /* 3 registers */
-#define MCHAFE			0x112c0
-#define CSIEC			0x112e0
-#define DMIEC			0x112e4
-#define DDREC			0x112e8
-#define PEG0EC			0x112ec
-#define PEG1EC			0x112f0
-#define GFXEC			0x112f4
-#define RPPREVBSYTUPAVG		0x113b8
-#define RPPREVBSYTDNAVG		0x113bc
-#define ECR			0x11600
+#define SDEW			_MMIO(0x1124c)
+#define CSIEW0			_MMIO(0x11250)
+#define CSIEW1			_MMIO(0x11254)
+#define CSIEW2			_MMIO(0x11258)
+#define PEW(i)			_MMIO(0x1125c + (i) * 4) /* 5 registers */
+#define DEW(i)			_MMIO(0x11270 + (i) * 4) /* 3 registers */
+#define MCHAFE			_MMIO(0x112c0)
+#define CSIEC			_MMIO(0x112e0)
+#define DMIEC			_MMIO(0x112e4)
+#define DDREC			_MMIO(0x112e8)
+#define PEG0EC			_MMIO(0x112ec)
+#define PEG1EC			_MMIO(0x112f0)
+#define GFXEC			_MMIO(0x112f4)
+#define RPPREVBSYTUPAVG		_MMIO(0x113b8)
+#define RPPREVBSYTDNAVG		_MMIO(0x113bc)
+#define ECR			_MMIO(0x11600)
 #define   ECR_GPFE		(1<<31)
 #define   ECR_IMONE		(1<<30)
 #define   ECR_CAP_MASK		0x0000001f /* Event range, 0-31 */
-#define OGW0			0x11608
-#define OGW1			0x1160c
-#define EG0			0x11610
-#define EG1			0x11614
-#define EG2			0x11618
-#define EG3			0x1161c
-#define EG4			0x11620
-#define EG5			0x11624
-#define EG6			0x11628
-#define EG7			0x1162c
-#define PXW(i)			(0x11664 + (i) * 4) /* 4 registers */
-#define PXWL(i)			(0x11680 + (i) * 4) /* 8 registers */
-#define LCFUSE02		0x116c0
+#define OGW0			_MMIO(0x11608)
+#define OGW1			_MMIO(0x1160c)
+#define EG0			_MMIO(0x11610)
+#define EG1			_MMIO(0x11614)
+#define EG2			_MMIO(0x11618)
+#define EG3			_MMIO(0x1161c)
+#define EG4			_MMIO(0x11620)
+#define EG5			_MMIO(0x11624)
+#define EG6			_MMIO(0x11628)
+#define EG7			_MMIO(0x1162c)
+#define PXW(i)			_MMIO(0x11664 + (i) * 4) /* 4 registers */
+#define PXWL(i)			_MMIO(0x11680 + (i) * 8) /* 8 registers */
+#define LCFUSE02		_MMIO(0x116c0)
 #define   LCFUSE_HIV_MASK	0x000000ff
-#define CSIPLL0			0x12c10
-#define DDRMPLL1		0X12c20
-#define PEG_BAND_GAP_DATA	0x14d68
+#define CSIPLL0			_MMIO(0x12c10)
+#define DDRMPLL1		_MMIO(0X12c20)
+#define PEG_BAND_GAP_DATA	_MMIO(0x14d68)
 
-#define GEN6_GT_THREAD_STATUS_REG 0x13805c
+#define GEN6_GT_THREAD_STATUS_REG _MMIO(0x13805c)
 #define GEN6_GT_THREAD_STATUS_CORE_MASK 0x7
 
-#define GEN6_GT_PERF_STATUS	(MCHBAR_MIRROR_BASE_SNB + 0x5948)
-#define BXT_GT_PERF_STATUS      (MCHBAR_MIRROR_BASE_SNB + 0x7070)
-#define GEN6_RP_STATE_LIMITS	(MCHBAR_MIRROR_BASE_SNB + 0x5994)
-#define GEN6_RP_STATE_CAP	(MCHBAR_MIRROR_BASE_SNB + 0x5998)
-#define BXT_RP_STATE_CAP        0x138170
+#define GEN6_GT_PERF_STATUS	_MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5948)
+#define BXT_GT_PERF_STATUS      _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x7070)
+#define GEN6_RP_STATE_LIMITS	_MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5994)
+#define GEN6_RP_STATE_CAP	_MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5998)
+#define BXT_RP_STATE_CAP        _MMIO(0x138170)
 
 #define INTERVAL_1_28_US(us)	(((us) * 100) >> 7)
 #define INTERVAL_1_33_US(us)	(((us) * 3)   >> 2)
@@ -2850,7 +2910,7 @@
 /*
  * Logical Context regs
  */
-#define CCID			0x2180
+#define CCID			_MMIO(0x2180)
 #define   CCID_EN		(1<<0)
 /*
  * Notes on SNB/IVB/VLV context size:
@@ -2865,7 +2925,7 @@
  * - GT1 size just indicates how much of render context
  *   doesn't need saving on GT1
  */
-#define CXT_SIZE		0x21a0
+#define CXT_SIZE		_MMIO(0x21a0)
 #define GEN6_CXT_POWER_SIZE(cxt_reg)	(((cxt_reg) >> 24) & 0x3f)
 #define GEN6_CXT_RING_SIZE(cxt_reg)	(((cxt_reg) >> 18) & 0x3f)
 #define GEN6_CXT_RENDER_SIZE(cxt_reg)	(((cxt_reg) >> 12) & 0x3f)
@@ -2874,7 +2934,7 @@
 #define GEN6_CXT_TOTAL_SIZE(cxt_reg)	(GEN6_CXT_RING_SIZE(cxt_reg) + \
 					GEN6_CXT_EXTENDED_SIZE(cxt_reg) + \
 					GEN6_CXT_PIPELINE_SIZE(cxt_reg))
-#define GEN7_CXT_SIZE		0x21a8
+#define GEN7_CXT_SIZE		_MMIO(0x21a8)
 #define GEN7_CXT_POWER_SIZE(ctx_reg)	(((ctx_reg) >> 25) & 0x7f)
 #define GEN7_CXT_RING_SIZE(ctx_reg)	(((ctx_reg) >> 22) & 0x7)
 #define GEN7_CXT_RENDER_SIZE(ctx_reg)	(((ctx_reg) >> 16) & 0x3f)
@@ -2894,23 +2954,23 @@
 /* Same as Haswell, but 72064 bytes now. */
 #define GEN8_CXT_TOTAL_SIZE		(18 * PAGE_SIZE)
 
-#define CHV_CLK_CTL1			0x101100
-#define VLV_CLK_CTL2			0x101104
+#define CHV_CLK_CTL1			_MMIO(0x101100)
+#define VLV_CLK_CTL2			_MMIO(0x101104)
 #define   CLK_CTL2_CZCOUNT_30NS_SHIFT	28
 
 /*
  * Overlay regs
  */
 
-#define OVADD			0x30000
-#define DOVSTA			0x30008
+#define OVADD			_MMIO(0x30000)
+#define DOVSTA			_MMIO(0x30008)
 #define OC_BUF			(0x3<<20)
-#define OGAMC5			0x30010
-#define OGAMC4			0x30014
-#define OGAMC3			0x30018
-#define OGAMC2			0x3001c
-#define OGAMC1			0x30020
-#define OGAMC0			0x30024
+#define OGAMC5			_MMIO(0x30010)
+#define OGAMC4			_MMIO(0x30014)
+#define OGAMC3			_MMIO(0x30018)
+#define OGAMC2			_MMIO(0x3001c)
+#define OGAMC1			_MMIO(0x30020)
+#define OGAMC0			_MMIO(0x30024)
 
 /*
  * Display engine regs
@@ -2970,28 +3030,18 @@
 #define _PIPE_CRC_RES_4_B_IVB		0x61070
 #define _PIPE_CRC_RES_5_B_IVB		0x61074
 
-#define PIPE_CRC_CTL(pipe) _TRANSCODER2(pipe, _PIPE_CRC_CTL_A)
-#define PIPE_CRC_RES_1_IVB(pipe)	\
-	_TRANSCODER2(pipe, _PIPE_CRC_RES_1_A_IVB)
-#define PIPE_CRC_RES_2_IVB(pipe)	\
-	_TRANSCODER2(pipe, _PIPE_CRC_RES_2_A_IVB)
-#define PIPE_CRC_RES_3_IVB(pipe)	\
-	_TRANSCODER2(pipe, _PIPE_CRC_RES_3_A_IVB)
-#define PIPE_CRC_RES_4_IVB(pipe)	\
-	_TRANSCODER2(pipe, _PIPE_CRC_RES_4_A_IVB)
-#define PIPE_CRC_RES_5_IVB(pipe)	\
-	_TRANSCODER2(pipe, _PIPE_CRC_RES_5_A_IVB)
+#define PIPE_CRC_CTL(pipe)		_MMIO_TRANS2(pipe, _PIPE_CRC_CTL_A)
+#define PIPE_CRC_RES_1_IVB(pipe)	_MMIO_TRANS2(pipe, _PIPE_CRC_RES_1_A_IVB)
+#define PIPE_CRC_RES_2_IVB(pipe)	_MMIO_TRANS2(pipe, _PIPE_CRC_RES_2_A_IVB)
+#define PIPE_CRC_RES_3_IVB(pipe)	_MMIO_TRANS2(pipe, _PIPE_CRC_RES_3_A_IVB)
+#define PIPE_CRC_RES_4_IVB(pipe)	_MMIO_TRANS2(pipe, _PIPE_CRC_RES_4_A_IVB)
+#define PIPE_CRC_RES_5_IVB(pipe)	_MMIO_TRANS2(pipe, _PIPE_CRC_RES_5_A_IVB)
 
-#define PIPE_CRC_RES_RED(pipe) \
-	_TRANSCODER2(pipe, _PIPE_CRC_RES_RED_A)
-#define PIPE_CRC_RES_GREEN(pipe) \
-	_TRANSCODER2(pipe, _PIPE_CRC_RES_GREEN_A)
-#define PIPE_CRC_RES_BLUE(pipe) \
-	_TRANSCODER2(pipe, _PIPE_CRC_RES_BLUE_A)
-#define PIPE_CRC_RES_RES1_I915(pipe) \
-	_TRANSCODER2(pipe, _PIPE_CRC_RES_RES1_A_I915)
-#define PIPE_CRC_RES_RES2_G4X(pipe) \
-	_TRANSCODER2(pipe, _PIPE_CRC_RES_RES2_A_G4X)
+#define PIPE_CRC_RES_RED(pipe)		_MMIO_TRANS2(pipe, _PIPE_CRC_RES_RED_A)
+#define PIPE_CRC_RES_GREEN(pipe)	_MMIO_TRANS2(pipe, _PIPE_CRC_RES_GREEN_A)
+#define PIPE_CRC_RES_BLUE(pipe)		_MMIO_TRANS2(pipe, _PIPE_CRC_RES_BLUE_A)
+#define PIPE_CRC_RES_RES1_I915(pipe)	_MMIO_TRANS2(pipe, _PIPE_CRC_RES_RES1_A_I915)
+#define PIPE_CRC_RES_RES2_G4X(pipe)	_MMIO_TRANS2(pipe, _PIPE_CRC_RES_RES2_A_G4X)
 
 /* Pipe A timing regs */
 #define _HTOTAL_A	0x60000
@@ -3023,20 +3073,20 @@
 #define CHV_TRANSCODER_C_OFFSET 0x63000
 #define TRANSCODER_EDP_OFFSET 0x6f000
 
-#define _TRANSCODER2(pipe, reg) (dev_priv->info.trans_offsets[(pipe)] - \
+#define _MMIO_TRANS2(pipe, reg) _MMIO(dev_priv->info.trans_offsets[(pipe)] - \
 	dev_priv->info.trans_offsets[TRANSCODER_A] + (reg) + \
 	dev_priv->info.display_mmio_offset)
 
-#define HTOTAL(trans) _TRANSCODER2(trans, _HTOTAL_A)
-#define HBLANK(trans) _TRANSCODER2(trans, _HBLANK_A)
-#define HSYNC(trans) _TRANSCODER2(trans, _HSYNC_A)
-#define VTOTAL(trans) _TRANSCODER2(trans, _VTOTAL_A)
-#define VBLANK(trans) _TRANSCODER2(trans, _VBLANK_A)
-#define VSYNC(trans) _TRANSCODER2(trans, _VSYNC_A)
-#define BCLRPAT(trans) _TRANSCODER2(trans, _BCLRPAT_A)
-#define VSYNCSHIFT(trans) _TRANSCODER2(trans, _VSYNCSHIFT_A)
-#define PIPESRC(trans) _TRANSCODER2(trans, _PIPEASRC)
-#define PIPE_MULT(trans) _TRANSCODER2(trans, _PIPE_MULT_A)
+#define HTOTAL(trans)		_MMIO_TRANS2(trans, _HTOTAL_A)
+#define HBLANK(trans)		_MMIO_TRANS2(trans, _HBLANK_A)
+#define HSYNC(trans)		_MMIO_TRANS2(trans, _HSYNC_A)
+#define VTOTAL(trans)		_MMIO_TRANS2(trans, _VTOTAL_A)
+#define VBLANK(trans)		_MMIO_TRANS2(trans, _VBLANK_A)
+#define VSYNC(trans)		_MMIO_TRANS2(trans, _VSYNC_A)
+#define BCLRPAT(trans)		_MMIO_TRANS2(trans, _BCLRPAT_A)
+#define VSYNCSHIFT(trans)	_MMIO_TRANS2(trans, _VSYNCSHIFT_A)
+#define PIPESRC(trans)		_MMIO_TRANS2(trans, _PIPEASRC)
+#define PIPE_MULT(trans)	_MMIO_TRANS2(trans, _PIPE_MULT_A)
 
 /* VLV eDP PSR registers */
 #define _PSRCTLA				(VLV_DISPLAY_BASE + 0x60090)
@@ -3052,14 +3102,14 @@
 #define  VLV_EDP_PSR_DBL_FRAME			(1<<10)
 #define  VLV_EDP_PSR_FRAME_COUNT_MASK		(0xff<<16)
 #define  VLV_EDP_PSR_IDLE_FRAME_SHIFT		16
-#define VLV_PSRCTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
+#define VLV_PSRCTL(pipe)	_MMIO_PIPE(pipe, _PSRCTLA, _PSRCTLB)
 
 #define _VSCSDPA			(VLV_DISPLAY_BASE + 0x600a0)
 #define _VSCSDPB			(VLV_DISPLAY_BASE + 0x610a0)
 #define  VLV_EDP_PSR_SDP_FREQ_MASK	(3<<30)
 #define  VLV_EDP_PSR_SDP_FREQ_ONCE	(1<<31)
 #define  VLV_EDP_PSR_SDP_FREQ_EVFRAME	(1<<30)
-#define VLV_VSCSDP(pipe)	_PIPE(pipe, _VSCSDPA, _VSCSDPB)
+#define VLV_VSCSDP(pipe)	_MMIO_PIPE(pipe, _VSCSDPA, _VSCSDPB)
 
 #define _PSRSTATA			(VLV_DISPLAY_BASE + 0x60094)
 #define _PSRSTATB			(VLV_DISPLAY_BASE + 0x61094)
@@ -3072,11 +3122,12 @@
 #define  VLV_EDP_PSR_ACTIVE_SF_UPDATE	(4<<0)
 #define  VLV_EDP_PSR_EXIT		(5<<0)
 #define  VLV_EDP_PSR_IN_TRANS		(1<<7)
-#define VLV_PSRSTAT(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
+#define VLV_PSRSTAT(pipe)	_MMIO_PIPE(pipe, _PSRSTATA, _PSRSTATB)
 
 /* HSW+ eDP PSR registers */
-#define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
-#define EDP_PSR_CTL(dev)			(EDP_PSR_BASE(dev) + 0)
+#define HSW_EDP_PSR_BASE	0x64800
+#define BDW_EDP_PSR_BASE	0x6f800
+#define EDP_PSR_CTL				_MMIO(dev_priv->psr_mmio_base + 0)
 #define   EDP_PSR_ENABLE			(1<<31)
 #define   BDW_PSR_SINGLE_FRAME			(1<<30)
 #define   EDP_PSR_LINK_STANDBY			(1<<27)
@@ -3099,14 +3150,10 @@
 #define   EDP_PSR_TP1_TIME_0us			(3<<4)
 #define   EDP_PSR_IDLE_FRAME_SHIFT		0
 
-#define EDP_PSR_AUX_CTL(dev)			(EDP_PSR_BASE(dev) + 0x10)
-#define EDP_PSR_AUX_DATA1(dev)			(EDP_PSR_BASE(dev) + 0x14)
-#define EDP_PSR_AUX_DATA2(dev)			(EDP_PSR_BASE(dev) + 0x18)
-#define EDP_PSR_AUX_DATA3(dev)			(EDP_PSR_BASE(dev) + 0x1c)
-#define EDP_PSR_AUX_DATA4(dev)			(EDP_PSR_BASE(dev) + 0x20)
-#define EDP_PSR_AUX_DATA5(dev)			(EDP_PSR_BASE(dev) + 0x24)
+#define EDP_PSR_AUX_CTL				_MMIO(dev_priv->psr_mmio_base + 0x10)
+#define EDP_PSR_AUX_DATA(i)			_MMIO(dev_priv->psr_mmio_base + 0x14 + (i) * 4) /* 5 registers */
 
-#define EDP_PSR_STATUS_CTL(dev)			(EDP_PSR_BASE(dev) + 0x40)
+#define EDP_PSR_STATUS_CTL			_MMIO(dev_priv->psr_mmio_base + 0x40)
 #define   EDP_PSR_STATUS_STATE_MASK		(7<<29)
 #define   EDP_PSR_STATUS_STATE_IDLE		(0<<29)
 #define   EDP_PSR_STATUS_STATE_SRDONACK		(1<<29)
@@ -3130,15 +3177,15 @@
 #define   EDP_PSR_STATUS_SENDING_TP1		(1<<4)
 #define   EDP_PSR_STATUS_IDLE_MASK		0xf
 
-#define EDP_PSR_PERF_CNT(dev)		(EDP_PSR_BASE(dev) + 0x44)
+#define EDP_PSR_PERF_CNT		_MMIO(dev_priv->psr_mmio_base + 0x44)
 #define   EDP_PSR_PERF_CNT_MASK		0xffffff
 
-#define EDP_PSR_DEBUG_CTL(dev)		(EDP_PSR_BASE(dev) + 0x60)
+#define EDP_PSR_DEBUG_CTL		_MMIO(dev_priv->psr_mmio_base + 0x60)
 #define   EDP_PSR_DEBUG_MASK_LPSP	(1<<27)
 #define   EDP_PSR_DEBUG_MASK_MEMUP	(1<<26)
 #define   EDP_PSR_DEBUG_MASK_HPD	(1<<25)
 
-#define EDP_PSR2_CTL			0x6f900
+#define EDP_PSR2_CTL			_MMIO(0x6f900)
 #define   EDP_PSR2_ENABLE		(1<<31)
 #define   EDP_SU_TRACK_ENABLE		(1<<30)
 #define   EDP_MAX_SU_DISABLE_TIME(t)	((t)<<20)
@@ -3153,9 +3200,9 @@
 #define   EDP_PSR2_IDLE_MASK		0xf
 
 /* VGA port control */
-#define ADPA			0x61100
-#define PCH_ADPA                0xe1100
-#define VLV_ADPA		(VLV_DISPLAY_BASE + ADPA)
+#define ADPA			_MMIO(0x61100)
+#define PCH_ADPA                _MMIO(0xe1100)
+#define VLV_ADPA		_MMIO(VLV_DISPLAY_BASE + 0x61100)
 
 #define   ADPA_DAC_ENABLE	(1<<31)
 #define   ADPA_DAC_DISABLE	0
@@ -3201,7 +3248,7 @@
 
 
 /* Hotplug control (945+ only) */
-#define PORT_HOTPLUG_EN		(dev_priv->info.display_mmio_offset + 0x61110)
+#define PORT_HOTPLUG_EN		_MMIO(dev_priv->info.display_mmio_offset + 0x61110)
 #define   PORTB_HOTPLUG_INT_EN			(1 << 29)
 #define   PORTC_HOTPLUG_INT_EN			(1 << 28)
 #define   PORTD_HOTPLUG_INT_EN			(1 << 27)
@@ -3231,7 +3278,7 @@
 #define CRT_HOTPLUG_DETECT_VOLTAGE_325MV	(0 << 2)
 #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV	(1 << 2)
 
-#define PORT_HOTPLUG_STAT	(dev_priv->info.display_mmio_offset + 0x61114)
+#define PORT_HOTPLUG_STAT	_MMIO(dev_priv->info.display_mmio_offset + 0x61114)
 /*
  * HDMI/DP bits are gen4+
  *
@@ -3296,21 +3343,23 @@
 
 /* SDVO and HDMI port control.
  * The same register may be used for SDVO or HDMI */
-#define GEN3_SDVOB	0x61140
-#define GEN3_SDVOC	0x61160
+#define _GEN3_SDVOB	0x61140
+#define _GEN3_SDVOC	0x61160
+#define GEN3_SDVOB	_MMIO(_GEN3_SDVOB)
+#define GEN3_SDVOC	_MMIO(_GEN3_SDVOC)
 #define GEN4_HDMIB	GEN3_SDVOB
 #define GEN4_HDMIC	GEN3_SDVOC
-#define VLV_HDMIB	(VLV_DISPLAY_BASE + GEN4_HDMIB)
-#define VLV_HDMIC	(VLV_DISPLAY_BASE + GEN4_HDMIC)
-#define CHV_HDMID	(VLV_DISPLAY_BASE + 0x6116C)
-#define PCH_SDVOB	0xe1140
+#define VLV_HDMIB	_MMIO(VLV_DISPLAY_BASE + 0x61140)
+#define VLV_HDMIC	_MMIO(VLV_DISPLAY_BASE + 0x61160)
+#define CHV_HDMID	_MMIO(VLV_DISPLAY_BASE + 0x6116C)
+#define PCH_SDVOB	_MMIO(0xe1140)
 #define PCH_HDMIB	PCH_SDVOB
-#define PCH_HDMIC	0xe1150
-#define PCH_HDMID	0xe1160
+#define PCH_HDMIC	_MMIO(0xe1150)
+#define PCH_HDMID	_MMIO(0xe1160)
 
-#define PORT_DFT_I9XX				0x61150
+#define PORT_DFT_I9XX				_MMIO(0x61150)
 #define   DC_BALANCE_RESET			(1 << 25)
-#define PORT_DFT2_G4X		(dev_priv->info.display_mmio_offset + 0x61154)
+#define PORT_DFT2_G4X		_MMIO(dev_priv->info.display_mmio_offset + 0x61154)
 #define   DC_BALANCE_RESET_VLV			(1 << 31)
 #define   PIPE_SCRAMBLE_RESET_MASK		((1 << 14) | (0x3 << 0))
 #define   PIPE_C_SCRAMBLE_RESET			(1 << 14) /* chv */
@@ -3370,9 +3419,12 @@
 
 
 /* DVO port control */
-#define DVOA			0x61120
-#define DVOB			0x61140
-#define DVOC			0x61160
+#define _DVOA			0x61120
+#define DVOA			_MMIO(_DVOA)
+#define _DVOB			0x61140
+#define DVOB			_MMIO(_DVOB)
+#define _DVOC			0x61160
+#define DVOC			_MMIO(_DVOC)
 #define   DVO_ENABLE			(1 << 31)
 #define   DVO_PIPE_B_SELECT		(1 << 30)
 #define   DVO_PIPE_STALL_UNUSED		(0 << 28)
@@ -3397,14 +3449,14 @@
 #define   DVO_OUTPUT_CSTATE_PIXELS	(1 << 1)	/* SDG only */
 #define   DVO_OUTPUT_SOURCE_SIZE_PIXELS	(1 << 0)	/* SDG only */
 #define   DVO_PRESERVE_MASK		(0x7<<24)
-#define DVOA_SRCDIM		0x61124
-#define DVOB_SRCDIM		0x61144
-#define DVOC_SRCDIM		0x61164
+#define DVOA_SRCDIM		_MMIO(0x61124)
+#define DVOB_SRCDIM		_MMIO(0x61144)
+#define DVOC_SRCDIM		_MMIO(0x61164)
 #define   DVO_SRCDIM_HORIZONTAL_SHIFT	12
 #define   DVO_SRCDIM_VERTICAL_SHIFT	0
 
 /* LVDS port control */
-#define LVDS			0x61180
+#define LVDS			_MMIO(0x61180)
 /*
  * Enables the LVDS port.  This bit must be set before DPLLs are enabled, as
  * the DPLL semantics change when the LVDS is assigned to that pipe.
@@ -3454,13 +3506,13 @@
 #define   LVDS_B0B3_POWER_UP		(3 << 2)
 
 /* Video Data Island Packet control */
-#define VIDEO_DIP_DATA		0x61178
+#define VIDEO_DIP_DATA		_MMIO(0x61178)
 /* Read the description of VIDEO_DIP_DATA (before Haswell) or VIDEO_DIP_ECC
  * (Haswell and newer) to see which VIDEO_DIP_DATA byte corresponds to each byte
  * of the infoframe structure specified by CEA-861. */
 #define   VIDEO_DIP_DATA_SIZE	32
 #define   VIDEO_DIP_VSC_DATA_SIZE	36
-#define VIDEO_DIP_CTL		0x61170
+#define VIDEO_DIP_CTL		_MMIO(0x61170)
 /* Pre HSW: */
 #define   VIDEO_DIP_ENABLE		(1 << 31)
 #define   VIDEO_DIP_PORT(port)		((port) << 29)
@@ -3487,7 +3539,7 @@
 #define   VIDEO_DIP_ENABLE_SPD_HSW	(1 << 0)
 
 /* Panel power sequencing */
-#define PP_STATUS	0x61200
+#define PP_STATUS	_MMIO(0x61200)
 #define   PP_ON		(1 << 31)
 /*
  * Indicates that all dependencies of the panel are on:
@@ -3513,14 +3565,14 @@
 #define   PP_SEQUENCE_STATE_ON_S1_2	(0xa << 0)
 #define   PP_SEQUENCE_STATE_ON_S1_3	(0xb << 0)
 #define   PP_SEQUENCE_STATE_RESET	(0xf << 0)
-#define PP_CONTROL	0x61204
+#define PP_CONTROL	_MMIO(0x61204)
 #define   POWER_TARGET_ON	(1 << 0)
-#define PP_ON_DELAYS	0x61208
-#define PP_OFF_DELAYS	0x6120c
-#define PP_DIVISOR	0x61210
+#define PP_ON_DELAYS	_MMIO(0x61208)
+#define PP_OFF_DELAYS	_MMIO(0x6120c)
+#define PP_DIVISOR	_MMIO(0x61210)
 
 /* Panel fitting */
-#define PFIT_CONTROL	(dev_priv->info.display_mmio_offset + 0x61230)
+#define PFIT_CONTROL	_MMIO(dev_priv->info.display_mmio_offset + 0x61230)
 #define   PFIT_ENABLE		(1 << 31)
 #define   PFIT_PIPE_MASK	(3 << 29)
 #define   PFIT_PIPE_SHIFT	29
@@ -3538,7 +3590,7 @@
 #define   PFIT_SCALING_PROGRAMMED (1 << 26)
 #define   PFIT_SCALING_PILLAR	(2 << 26)
 #define   PFIT_SCALING_LETTER	(3 << 26)
-#define PFIT_PGM_RATIOS	(dev_priv->info.display_mmio_offset + 0x61234)
+#define PFIT_PGM_RATIOS _MMIO(dev_priv->info.display_mmio_offset + 0x61234)
 /* Pre-965 */
 #define		PFIT_VERT_SCALE_SHIFT		20
 #define		PFIT_VERT_SCALE_MASK		0xfff00000
@@ -3550,25 +3602,25 @@
 #define		PFIT_HORIZ_SCALE_SHIFT_965	0
 #define		PFIT_HORIZ_SCALE_MASK_965	0x00001fff
 
-#define PFIT_AUTO_RATIOS (dev_priv->info.display_mmio_offset + 0x61238)
+#define PFIT_AUTO_RATIOS _MMIO(dev_priv->info.display_mmio_offset + 0x61238)
 
 #define _VLV_BLC_PWM_CTL2_A (dev_priv->info.display_mmio_offset + 0x61250)
 #define _VLV_BLC_PWM_CTL2_B (dev_priv->info.display_mmio_offset + 0x61350)
-#define VLV_BLC_PWM_CTL2(pipe) _PIPE(pipe, _VLV_BLC_PWM_CTL2_A, \
-				     _VLV_BLC_PWM_CTL2_B)
+#define VLV_BLC_PWM_CTL2(pipe) _MMIO_PIPE(pipe, _VLV_BLC_PWM_CTL2_A, \
+					 _VLV_BLC_PWM_CTL2_B)
 
 #define _VLV_BLC_PWM_CTL_A (dev_priv->info.display_mmio_offset + 0x61254)
 #define _VLV_BLC_PWM_CTL_B (dev_priv->info.display_mmio_offset + 0x61354)
-#define VLV_BLC_PWM_CTL(pipe) _PIPE(pipe, _VLV_BLC_PWM_CTL_A, \
-				    _VLV_BLC_PWM_CTL_B)
+#define VLV_BLC_PWM_CTL(pipe) _MMIO_PIPE(pipe, _VLV_BLC_PWM_CTL_A, \
+					_VLV_BLC_PWM_CTL_B)
 
 #define _VLV_BLC_HIST_CTL_A (dev_priv->info.display_mmio_offset + 0x61260)
 #define _VLV_BLC_HIST_CTL_B (dev_priv->info.display_mmio_offset + 0x61360)
-#define VLV_BLC_HIST_CTL(pipe) _PIPE(pipe, _VLV_BLC_HIST_CTL_A, \
-				     _VLV_BLC_HIST_CTL_B)
+#define VLV_BLC_HIST_CTL(pipe) _MMIO_PIPE(pipe, _VLV_BLC_HIST_CTL_A, \
+					 _VLV_BLC_HIST_CTL_B)
 
 /* Backlight control */
-#define BLC_PWM_CTL2	(dev_priv->info.display_mmio_offset + 0x61250) /* 965+ only */
+#define BLC_PWM_CTL2	_MMIO(dev_priv->info.display_mmio_offset + 0x61250) /* 965+ only */
 #define   BLM_PWM_ENABLE		(1 << 31)
 #define   BLM_COMBINATION_MODE		(1 << 30) /* gen4 only */
 #define   BLM_PIPE_SELECT		(1 << 29)
@@ -3591,7 +3643,7 @@
 #define   BLM_PHASE_IN_COUNT_MASK	(0xff << 8)
 #define   BLM_PHASE_IN_INCR_SHIFT	(0)
 #define   BLM_PHASE_IN_INCR_MASK	(0xff << 0)
-#define BLC_PWM_CTL	(dev_priv->info.display_mmio_offset + 0x61254)
+#define BLC_PWM_CTL	_MMIO(dev_priv->info.display_mmio_offset + 0x61254)
 /*
  * This is the most significant 15 bits of the number of backlight cycles in a
  * complete cycle of the modulated backlight control.
@@ -3613,25 +3665,25 @@
 #define   BACKLIGHT_DUTY_CYCLE_MASK_PNV		(0xfffe)
 #define   BLM_POLARITY_PNV			(1 << 0) /* pnv only */
 
-#define BLC_HIST_CTL	(dev_priv->info.display_mmio_offset + 0x61260)
+#define BLC_HIST_CTL	_MMIO(dev_priv->info.display_mmio_offset + 0x61260)
 #define  BLM_HISTOGRAM_ENABLE			(1 << 31)
 
 /* New registers for PCH-split platforms. Safe where new bits show up, the
  * register layout machtes with gen4 BLC_PWM_CTL[12]. */
-#define BLC_PWM_CPU_CTL2	0x48250
-#define BLC_PWM_CPU_CTL		0x48254
+#define BLC_PWM_CPU_CTL2	_MMIO(0x48250)
+#define BLC_PWM_CPU_CTL		_MMIO(0x48254)
 
-#define HSW_BLC_PWM2_CTL	0x48350
+#define HSW_BLC_PWM2_CTL	_MMIO(0x48350)
 
 /* PCH CTL1 is totally different, all but the below bits are reserved. CTL2 is
  * like the normal CTL from gen4 and earlier. Hooray for confusing naming. */
-#define BLC_PWM_PCH_CTL1	0xc8250
+#define BLC_PWM_PCH_CTL1	_MMIO(0xc8250)
 #define   BLM_PCH_PWM_ENABLE			(1 << 31)
 #define   BLM_PCH_OVERRIDE_ENABLE		(1 << 30)
 #define   BLM_PCH_POLARITY			(1 << 29)
-#define BLC_PWM_PCH_CTL2	0xc8254
+#define BLC_PWM_PCH_CTL2	_MMIO(0xc8254)
 
-#define UTIL_PIN_CTL		0x48400
+#define UTIL_PIN_CTL		_MMIO(0x48400)
 #define   UTIL_PIN_ENABLE	(1 << 31)
 
 #define   UTIL_PIN_PIPE(x)     ((x) << 29)
@@ -3651,18 +3703,18 @@
 #define _BXT_BLC_PWM_FREQ2			0xC8354
 #define _BXT_BLC_PWM_DUTY2			0xC8358
 
-#define BXT_BLC_PWM_CTL(controller)    _PIPE(controller, \
+#define BXT_BLC_PWM_CTL(controller)    _MMIO_PIPE(controller,		\
 					_BXT_BLC_PWM_CTL1, _BXT_BLC_PWM_CTL2)
-#define BXT_BLC_PWM_FREQ(controller)   _PIPE(controller, \
+#define BXT_BLC_PWM_FREQ(controller)   _MMIO_PIPE(controller, \
 					_BXT_BLC_PWM_FREQ1, _BXT_BLC_PWM_FREQ2)
-#define BXT_BLC_PWM_DUTY(controller)   _PIPE(controller, \
+#define BXT_BLC_PWM_DUTY(controller)   _MMIO_PIPE(controller, \
 					_BXT_BLC_PWM_DUTY1, _BXT_BLC_PWM_DUTY2)
 
-#define PCH_GTC_CTL		0xe7000
+#define PCH_GTC_CTL		_MMIO(0xe7000)
 #define   PCH_GTC_ENABLE	(1 << 31)
 
 /* TV port control */
-#define TV_CTL			0x68000
+#define TV_CTL			_MMIO(0x68000)
 /* Enables the TV encoder */
 # define TV_ENC_ENABLE			(1 << 31)
 /* Sources the TV encoder input from pipe B instead of A. */
@@ -3729,7 +3781,7 @@
 # define TV_TEST_MODE_MONITOR_DETECT	(7 << 0)
 # define TV_TEST_MODE_MASK		(7 << 0)
 
-#define TV_DAC			0x68004
+#define TV_DAC			_MMIO(0x68004)
 # define TV_DAC_SAVE		0x00ffff00
 /*
  * Reports that DAC state change logic has reported change (RO).
@@ -3780,13 +3832,13 @@
  * where 2-bit exponents are unsigned n, and 3-bit exponents are signed n with
  * -1 (0x3) being the only legal negative value.
  */
-#define TV_CSC_Y		0x68010
+#define TV_CSC_Y		_MMIO(0x68010)
 # define TV_RY_MASK			0x07ff0000
 # define TV_RY_SHIFT			16
 # define TV_GY_MASK			0x00000fff
 # define TV_GY_SHIFT			0
 
-#define TV_CSC_Y2		0x68014
+#define TV_CSC_Y2		_MMIO(0x68014)
 # define TV_BY_MASK			0x07ff0000
 # define TV_BY_SHIFT			16
 /*
@@ -3797,13 +3849,13 @@
 # define TV_AY_MASK			0x000003ff
 # define TV_AY_SHIFT			0
 
-#define TV_CSC_U		0x68018
+#define TV_CSC_U		_MMIO(0x68018)
 # define TV_RU_MASK			0x07ff0000
 # define TV_RU_SHIFT			16
 # define TV_GU_MASK			0x000007ff
 # define TV_GU_SHIFT			0
 
-#define TV_CSC_U2		0x6801c
+#define TV_CSC_U2		_MMIO(0x6801c)
 # define TV_BU_MASK			0x07ff0000
 # define TV_BU_SHIFT			16
 /*
@@ -3814,13 +3866,13 @@
 # define TV_AU_MASK			0x000003ff
 # define TV_AU_SHIFT			0
 
-#define TV_CSC_V		0x68020
+#define TV_CSC_V		_MMIO(0x68020)
 # define TV_RV_MASK			0x0fff0000
 # define TV_RV_SHIFT			16
 # define TV_GV_MASK			0x000007ff
 # define TV_GV_SHIFT			0
 
-#define TV_CSC_V2		0x68024
+#define TV_CSC_V2		_MMIO(0x68024)
 # define TV_BV_MASK			0x07ff0000
 # define TV_BV_SHIFT			16
 /*
@@ -3831,7 +3883,7 @@
 # define TV_AV_MASK			0x000007ff
 # define TV_AV_SHIFT			0
 
-#define TV_CLR_KNOBS		0x68028
+#define TV_CLR_KNOBS		_MMIO(0x68028)
 /* 2s-complement brightness adjustment */
 # define TV_BRIGHTNESS_MASK		0xff000000
 # define TV_BRIGHTNESS_SHIFT		24
@@ -3845,7 +3897,7 @@
 # define TV_HUE_MASK			0x000000ff
 # define TV_HUE_SHIFT			0
 
-#define TV_CLR_LEVEL		0x6802c
+#define TV_CLR_LEVEL		_MMIO(0x6802c)
 /* Controls the DAC level for black */
 # define TV_BLACK_LEVEL_MASK		0x01ff0000
 # define TV_BLACK_LEVEL_SHIFT		16
@@ -3853,7 +3905,7 @@
 # define TV_BLANK_LEVEL_MASK		0x000001ff
 # define TV_BLANK_LEVEL_SHIFT		0
 
-#define TV_H_CTL_1		0x68030
+#define TV_H_CTL_1		_MMIO(0x68030)
 /* Number of pixels in the hsync. */
 # define TV_HSYNC_END_MASK		0x1fff0000
 # define TV_HSYNC_END_SHIFT		16
@@ -3861,7 +3913,7 @@
 # define TV_HTOTAL_MASK			0x00001fff
 # define TV_HTOTAL_SHIFT		0
 
-#define TV_H_CTL_2		0x68034
+#define TV_H_CTL_2		_MMIO(0x68034)
 /* Enables the colorburst (needed for non-component color) */
 # define TV_BURST_ENA			(1 << 31)
 /* Offset of the colorburst from the start of hsync, in pixels minus one. */
@@ -3871,7 +3923,7 @@
 # define TV_HBURST_LEN_SHIFT		0
 # define TV_HBURST_LEN_MASK		0x0001fff
 
-#define TV_H_CTL_3		0x68038
+#define TV_H_CTL_3		_MMIO(0x68038)
 /* End of hblank, measured in pixels minus one from start of hsync */
 # define TV_HBLANK_END_SHIFT		16
 # define TV_HBLANK_END_MASK		0x1fff0000
@@ -3879,7 +3931,7 @@
 # define TV_HBLANK_START_SHIFT		0
 # define TV_HBLANK_START_MASK		0x0001fff
 
-#define TV_V_CTL_1		0x6803c
+#define TV_V_CTL_1		_MMIO(0x6803c)
 /* XXX */
 # define TV_NBR_END_SHIFT		16
 # define TV_NBR_END_MASK		0x07ff0000
@@ -3890,7 +3942,7 @@
 # define TV_VI_END_F2_SHIFT		0
 # define TV_VI_END_F2_MASK		0x0000003f
 
-#define TV_V_CTL_2		0x68040
+#define TV_V_CTL_2		_MMIO(0x68040)
 /* Length of vsync, in half lines */
 # define TV_VSYNC_LEN_MASK		0x07ff0000
 # define TV_VSYNC_LEN_SHIFT		16
@@ -3906,7 +3958,7 @@
 # define TV_VSYNC_START_F2_MASK		0x0000007f
 # define TV_VSYNC_START_F2_SHIFT	0
 
-#define TV_V_CTL_3		0x68044
+#define TV_V_CTL_3		_MMIO(0x68044)
 /* Enables generation of the equalization signal */
 # define TV_EQUAL_ENA			(1 << 31)
 /* Length of vsync, in half lines */
@@ -3924,7 +3976,7 @@
 # define TV_VEQ_START_F2_MASK		0x000007f
 # define TV_VEQ_START_F2_SHIFT		0
 
-#define TV_V_CTL_4		0x68048
+#define TV_V_CTL_4		_MMIO(0x68048)
 /*
  * Offset to start of vertical colorburst, measured in one less than the
  * number of lines from vertical start.
@@ -3938,7 +3990,7 @@
 # define TV_VBURST_END_F1_MASK		0x000000ff
 # define TV_VBURST_END_F1_SHIFT		0
 
-#define TV_V_CTL_5		0x6804c
+#define TV_V_CTL_5		_MMIO(0x6804c)
 /*
  * Offset to start of vertical colorburst, measured in one less than the
  * number of lines from vertical start.
@@ -3952,7 +4004,7 @@
 # define TV_VBURST_END_F2_MASK		0x000000ff
 # define TV_VBURST_END_F2_SHIFT		0
 
-#define TV_V_CTL_6		0x68050
+#define TV_V_CTL_6		_MMIO(0x68050)
 /*
  * Offset to start of vertical colorburst, measured in one less than the
  * number of lines from vertical start.
@@ -3966,7 +4018,7 @@
 # define TV_VBURST_END_F3_MASK		0x000000ff
 # define TV_VBURST_END_F3_SHIFT		0
 
-#define TV_V_CTL_7		0x68054
+#define TV_V_CTL_7		_MMIO(0x68054)
 /*
  * Offset to start of vertical colorburst, measured in one less than the
  * number of lines from vertical start.
@@ -3980,7 +4032,7 @@
 # define TV_VBURST_END_F4_MASK		0x000000ff
 # define TV_VBURST_END_F4_SHIFT		0
 
-#define TV_SC_CTL_1		0x68060
+#define TV_SC_CTL_1		_MMIO(0x68060)
 /* Turns on the first subcarrier phase generation DDA */
 # define TV_SC_DDA1_EN			(1 << 31)
 /* Turns on the first subcarrier phase generation DDA */
@@ -4002,7 +4054,7 @@
 # define TV_SCDDA1_INC_MASK		0x00000fff
 # define TV_SCDDA1_INC_SHIFT		0
 
-#define TV_SC_CTL_2		0x68064
+#define TV_SC_CTL_2		_MMIO(0x68064)
 /* Sets the rollover for the second subcarrier phase generation DDA */
 # define TV_SCDDA2_SIZE_MASK		0x7fff0000
 # define TV_SCDDA2_SIZE_SHIFT		16
@@ -4010,7 +4062,7 @@
 # define TV_SCDDA2_INC_MASK		0x00007fff
 # define TV_SCDDA2_INC_SHIFT		0
 
-#define TV_SC_CTL_3		0x68068
+#define TV_SC_CTL_3		_MMIO(0x68068)
 /* Sets the rollover for the third subcarrier phase generation DDA */
 # define TV_SCDDA3_SIZE_MASK		0x7fff0000
 # define TV_SCDDA3_SIZE_SHIFT		16
@@ -4018,7 +4070,7 @@
 # define TV_SCDDA3_INC_MASK		0x00007fff
 # define TV_SCDDA3_INC_SHIFT		0
 
-#define TV_WIN_POS		0x68070
+#define TV_WIN_POS		_MMIO(0x68070)
 /* X coordinate of the display from the start of horizontal active */
 # define TV_XPOS_MASK			0x1fff0000
 # define TV_XPOS_SHIFT			16
@@ -4026,7 +4078,7 @@
 # define TV_YPOS_MASK			0x00000fff
 # define TV_YPOS_SHIFT			0
 
-#define TV_WIN_SIZE		0x68074
+#define TV_WIN_SIZE		_MMIO(0x68074)
 /* Horizontal size of the display window, measured in pixels*/
 # define TV_XSIZE_MASK			0x1fff0000
 # define TV_XSIZE_SHIFT			16
@@ -4038,7 +4090,7 @@
 # define TV_YSIZE_MASK			0x00000fff
 # define TV_YSIZE_SHIFT			0
 
-#define TV_FILTER_CTL_1		0x68080
+#define TV_FILTER_CTL_1		_MMIO(0x68080)
 /*
  * Enables automatic scaling calculation.
  *
@@ -4071,7 +4123,7 @@
 # define TV_HSCALE_FRAC_MASK		0x00003fff
 # define TV_HSCALE_FRAC_SHIFT		0
 
-#define TV_FILTER_CTL_2		0x68084
+#define TV_FILTER_CTL_2		_MMIO(0x68084)
 /*
  * Sets the integer part of the 3.15 fixed-point vertical scaling factor.
  *
@@ -4087,7 +4139,7 @@
 # define TV_VSCALE_FRAC_MASK		0x00007fff
 # define TV_VSCALE_FRAC_SHIFT		0
 
-#define TV_FILTER_CTL_3		0x68088
+#define TV_FILTER_CTL_3		_MMIO(0x68088)
 /*
  * Sets the integer part of the 3.15 fixed-point vertical scaling factor.
  *
@@ -4107,7 +4159,7 @@
 # define TV_VSCALE_IP_FRAC_MASK		0x00007fff
 # define TV_VSCALE_IP_FRAC_SHIFT		0
 
-#define TV_CC_CONTROL		0x68090
+#define TV_CC_CONTROL		_MMIO(0x68090)
 # define TV_CC_ENABLE			(1 << 31)
 /*
  * Specifies which field to send the CC data in.
@@ -4123,7 +4175,7 @@
 # define TV_CC_LINE_MASK		0x0000003f
 # define TV_CC_LINE_SHIFT		0
 
-#define TV_CC_DATA		0x68094
+#define TV_CC_DATA		_MMIO(0x68094)
 # define TV_CC_RDY			(1 << 31)
 /* Second word of CC data to be transmitted. */
 # define TV_CC_DATA_2_MASK		0x007f0000
@@ -4132,20 +4184,20 @@
 # define TV_CC_DATA_1_MASK		0x0000007f
 # define TV_CC_DATA_1_SHIFT		0
 
-#define TV_H_LUMA(i)		(0x68100 + (i) * 4) /* 60 registers */
-#define TV_H_CHROMA(i)		(0x68200 + (i) * 4) /* 60 registers */
-#define TV_V_LUMA(i)		(0x68300 + (i) * 4) /* 43 registers */
-#define TV_V_CHROMA(i)		(0x68400 + (i) * 4) /* 43 registers */
+#define TV_H_LUMA(i)		_MMIO(0x68100 + (i) * 4) /* 60 registers */
+#define TV_H_CHROMA(i)		_MMIO(0x68200 + (i) * 4) /* 60 registers */
+#define TV_V_LUMA(i)		_MMIO(0x68300 + (i) * 4) /* 43 registers */
+#define TV_V_CHROMA(i)		_MMIO(0x68400 + (i) * 4) /* 43 registers */
 
 /* Display Port */
-#define DP_A				0x64000 /* eDP */
-#define DP_B				0x64100
-#define DP_C				0x64200
-#define DP_D				0x64300
+#define DP_A			_MMIO(0x64000) /* eDP */
+#define DP_B			_MMIO(0x64100)
+#define DP_C			_MMIO(0x64200)
+#define DP_D			_MMIO(0x64300)
 
-#define VLV_DP_B			(VLV_DISPLAY_BASE + DP_B)
-#define VLV_DP_C			(VLV_DISPLAY_BASE + DP_C)
-#define CHV_DP_D			(VLV_DISPLAY_BASE + DP_D)
+#define VLV_DP_B		_MMIO(VLV_DISPLAY_BASE + 0x64100)
+#define VLV_DP_C		_MMIO(VLV_DISPLAY_BASE + 0x64200)
+#define CHV_DP_D		_MMIO(VLV_DISPLAY_BASE + 0x64300)
 
 #define   DP_PORT_EN			(1 << 31)
 #define   DP_PIPEB_SELECT		(1 << 30)
@@ -4199,7 +4251,7 @@
 
 /* eDP */
 #define   DP_PLL_FREQ_270MHZ		(0 << 16)
-#define   DP_PLL_FREQ_160MHZ		(1 << 16)
+#define   DP_PLL_FREQ_162MHZ		(1 << 16)
 #define   DP_PLL_FREQ_MASK		(3 << 16)
 
 /* locked once port is enabled */
@@ -4232,33 +4284,36 @@
  * is 20 bytes in each direction, hence the 5 fixed
  * data registers
  */
-#define DPA_AUX_CH_CTL			0x64010
-#define DPA_AUX_CH_DATA1		0x64014
-#define DPA_AUX_CH_DATA2		0x64018
-#define DPA_AUX_CH_DATA3		0x6401c
-#define DPA_AUX_CH_DATA4		0x64020
-#define DPA_AUX_CH_DATA5		0x64024
+#define _DPA_AUX_CH_CTL		(dev_priv->info.display_mmio_offset + 0x64010)
+#define _DPA_AUX_CH_DATA1	(dev_priv->info.display_mmio_offset + 0x64014)
+#define _DPA_AUX_CH_DATA2	(dev_priv->info.display_mmio_offset + 0x64018)
+#define _DPA_AUX_CH_DATA3	(dev_priv->info.display_mmio_offset + 0x6401c)
+#define _DPA_AUX_CH_DATA4	(dev_priv->info.display_mmio_offset + 0x64020)
+#define _DPA_AUX_CH_DATA5	(dev_priv->info.display_mmio_offset + 0x64024)
 
-#define DPB_AUX_CH_CTL			0x64110
-#define DPB_AUX_CH_DATA1		0x64114
-#define DPB_AUX_CH_DATA2		0x64118
-#define DPB_AUX_CH_DATA3		0x6411c
-#define DPB_AUX_CH_DATA4		0x64120
-#define DPB_AUX_CH_DATA5		0x64124
+#define _DPB_AUX_CH_CTL		(dev_priv->info.display_mmio_offset + 0x64110)
+#define _DPB_AUX_CH_DATA1	(dev_priv->info.display_mmio_offset + 0x64114)
+#define _DPB_AUX_CH_DATA2	(dev_priv->info.display_mmio_offset + 0x64118)
+#define _DPB_AUX_CH_DATA3	(dev_priv->info.display_mmio_offset + 0x6411c)
+#define _DPB_AUX_CH_DATA4	(dev_priv->info.display_mmio_offset + 0x64120)
+#define _DPB_AUX_CH_DATA5	(dev_priv->info.display_mmio_offset + 0x64124)
 
-#define DPC_AUX_CH_CTL			0x64210
-#define DPC_AUX_CH_DATA1		0x64214
-#define DPC_AUX_CH_DATA2		0x64218
-#define DPC_AUX_CH_DATA3		0x6421c
-#define DPC_AUX_CH_DATA4		0x64220
-#define DPC_AUX_CH_DATA5		0x64224
+#define _DPC_AUX_CH_CTL		(dev_priv->info.display_mmio_offset + 0x64210)
+#define _DPC_AUX_CH_DATA1	(dev_priv->info.display_mmio_offset + 0x64214)
+#define _DPC_AUX_CH_DATA2	(dev_priv->info.display_mmio_offset + 0x64218)
+#define _DPC_AUX_CH_DATA3	(dev_priv->info.display_mmio_offset + 0x6421c)
+#define _DPC_AUX_CH_DATA4	(dev_priv->info.display_mmio_offset + 0x64220)
+#define _DPC_AUX_CH_DATA5	(dev_priv->info.display_mmio_offset + 0x64224)
 
-#define DPD_AUX_CH_CTL			0x64310
-#define DPD_AUX_CH_DATA1		0x64314
-#define DPD_AUX_CH_DATA2		0x64318
-#define DPD_AUX_CH_DATA3		0x6431c
-#define DPD_AUX_CH_DATA4		0x64320
-#define DPD_AUX_CH_DATA5		0x64324
+#define _DPD_AUX_CH_CTL		(dev_priv->info.display_mmio_offset + 0x64310)
+#define _DPD_AUX_CH_DATA1	(dev_priv->info.display_mmio_offset + 0x64314)
+#define _DPD_AUX_CH_DATA2	(dev_priv->info.display_mmio_offset + 0x64318)
+#define _DPD_AUX_CH_DATA3	(dev_priv->info.display_mmio_offset + 0x6431c)
+#define _DPD_AUX_CH_DATA4	(dev_priv->info.display_mmio_offset + 0x64320)
+#define _DPD_AUX_CH_DATA5	(dev_priv->info.display_mmio_offset + 0x64324)
+
+#define DP_AUX_CH_CTL(port)	_MMIO_PORT(port, _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL)
+#define DP_AUX_CH_DATA(port, i)	_MMIO(_PORT(port, _DPA_AUX_CH_DATA1, _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */
 
 #define   DP_AUX_CH_CTL_SEND_BUSY	    (1 << 31)
 #define   DP_AUX_CH_CTL_DONE		    (1 << 30)
@@ -4335,10 +4390,10 @@
 #define _PIPEB_LINK_N_G4X	0x71064
 #define   PIPEA_DP_LINK_N_MASK			(0xffffff)
 
-#define PIPE_DATA_M_G4X(pipe) _PIPE(pipe, _PIPEA_DATA_M_G4X, _PIPEB_DATA_M_G4X)
-#define PIPE_DATA_N_G4X(pipe) _PIPE(pipe, _PIPEA_DATA_N_G4X, _PIPEB_DATA_N_G4X)
-#define PIPE_LINK_M_G4X(pipe) _PIPE(pipe, _PIPEA_LINK_M_G4X, _PIPEB_LINK_M_G4X)
-#define PIPE_LINK_N_G4X(pipe) _PIPE(pipe, _PIPEA_LINK_N_G4X, _PIPEB_LINK_N_G4X)
+#define PIPE_DATA_M_G4X(pipe) _MMIO_PIPE(pipe, _PIPEA_DATA_M_G4X, _PIPEB_DATA_M_G4X)
+#define PIPE_DATA_N_G4X(pipe) _MMIO_PIPE(pipe, _PIPEA_DATA_N_G4X, _PIPEB_DATA_N_G4X)
+#define PIPE_LINK_M_G4X(pipe) _MMIO_PIPE(pipe, _PIPEA_LINK_M_G4X, _PIPEB_LINK_M_G4X)
+#define PIPE_LINK_N_G4X(pipe) _MMIO_PIPE(pipe, _PIPEA_LINK_N_G4X, _PIPEB_LINK_N_G4X)
 
 /* Display & cursor control */
 
@@ -4454,15 +4509,15 @@
  */
 #define PIPE_EDP_OFFSET	0x7f000
 
-#define _PIPE2(pipe, reg) (dev_priv->info.pipe_offsets[pipe] - \
+#define _MMIO_PIPE2(pipe, reg) _MMIO(dev_priv->info.pipe_offsets[pipe] - \
 	dev_priv->info.pipe_offsets[PIPE_A] + (reg) + \
 	dev_priv->info.display_mmio_offset)
 
-#define PIPECONF(pipe) _PIPE2(pipe, _PIPEACONF)
-#define PIPEDSL(pipe)  _PIPE2(pipe, _PIPEADSL)
-#define PIPEFRAME(pipe) _PIPE2(pipe, _PIPEAFRAMEHIGH)
-#define PIPEFRAMEPIXEL(pipe)  _PIPE2(pipe, _PIPEAFRAMEPIXEL)
-#define PIPESTAT(pipe) _PIPE2(pipe, _PIPEASTAT)
+#define PIPECONF(pipe)		_MMIO_PIPE2(pipe, _PIPEACONF)
+#define PIPEDSL(pipe)		_MMIO_PIPE2(pipe, _PIPEADSL)
+#define PIPEFRAME(pipe)		_MMIO_PIPE2(pipe, _PIPEAFRAMEHIGH)
+#define PIPEFRAMEPIXEL(pipe)	_MMIO_PIPE2(pipe, _PIPEAFRAMEPIXEL)
+#define PIPESTAT(pipe)		_MMIO_PIPE2(pipe, _PIPEASTAT)
 
 #define _PIPE_MISC_A			0x70030
 #define _PIPE_MISC_B			0x71030
@@ -4474,9 +4529,9 @@
 #define   PIPEMISC_DITHER_ENABLE	(1<<4)
 #define   PIPEMISC_DITHER_TYPE_MASK	(3<<2)
 #define   PIPEMISC_DITHER_TYPE_SP	(0<<2)
-#define PIPEMISC(pipe) _PIPE2(pipe, _PIPE_MISC_A)
+#define PIPEMISC(pipe)			_MMIO_PIPE2(pipe, _PIPE_MISC_A)
 
-#define VLV_DPFLIPSTAT				(VLV_DISPLAY_BASE + 0x70028)
+#define VLV_DPFLIPSTAT				_MMIO(VLV_DISPLAY_BASE + 0x70028)
 #define   PIPEB_LINE_COMPARE_INT_EN		(1<<29)
 #define   PIPEB_HLINE_INT_EN			(1<<28)
 #define   PIPEB_VBLANK_INT_EN			(1<<27)
@@ -4497,7 +4552,7 @@
 #define   SPRITEE_FLIPDONE_INT_EN		(1<<9)
 #define   PLANEC_FLIPDONE_INT_EN		(1<<8)
 
-#define DPINVGTT				(VLV_DISPLAY_BASE + 0x7002c) /* VLV/CHV only */
+#define DPINVGTT				_MMIO(VLV_DISPLAY_BASE + 0x7002c) /* VLV/CHV only */
 #define   SPRITEF_INVALID_GTT_INT_EN		(1<<27)
 #define   SPRITEE_INVALID_GTT_INT_EN		(1<<26)
 #define   PLANEC_INVALID_GTT_INT_EN		(1<<25)
@@ -4527,7 +4582,7 @@
 #define   DPINVGTT_STATUS_MASK			0xff
 #define   DPINVGTT_STATUS_MASK_CHV		0xfff
 
-#define DSPARB			(dev_priv->info.display_mmio_offset + 0x70030)
+#define DSPARB			_MMIO(dev_priv->info.display_mmio_offset + 0x70030)
 #define   DSPARB_CSTART_MASK	(0x7f << 7)
 #define   DSPARB_CSTART_SHIFT	7
 #define   DSPARB_BSTART_MASK	(0x7f)
@@ -4542,7 +4597,7 @@
 #define   DSPARB_SPRITEC_MASK_VLV	(0xff << 16)
 #define   DSPARB_SPRITED_SHIFT_VLV	24
 #define   DSPARB_SPRITED_MASK_VLV	(0xff << 24)
-#define DSPARB2			(VLV_DISPLAY_BASE + 0x70060) /* vlv/chv */
+#define DSPARB2				_MMIO(VLV_DISPLAY_BASE + 0x70060) /* vlv/chv */
 #define   DSPARB_SPRITEA_HI_SHIFT_VLV	0
 #define   DSPARB_SPRITEA_HI_MASK_VLV	(0x1 << 0)
 #define   DSPARB_SPRITEB_HI_SHIFT_VLV	4
@@ -4555,14 +4610,14 @@
 #define   DSPARB_SPRITEE_HI_MASK_VLV	(0x1 << 16)
 #define   DSPARB_SPRITEF_HI_SHIFT_VLV	20
 #define   DSPARB_SPRITEF_HI_MASK_VLV	(0x1 << 20)
-#define DSPARB3			(VLV_DISPLAY_BASE + 0x7006c) /* chv */
+#define DSPARB3				_MMIO(VLV_DISPLAY_BASE + 0x7006c) /* chv */
 #define   DSPARB_SPRITEE_SHIFT_VLV	0
 #define   DSPARB_SPRITEE_MASK_VLV	(0xff << 0)
 #define   DSPARB_SPRITEF_SHIFT_VLV	8
 #define   DSPARB_SPRITEF_MASK_VLV	(0xff << 8)
 
 /* pnv/gen4/g4x/vlv/chv */
-#define DSPFW1			(dev_priv->info.display_mmio_offset + 0x70034)
+#define DSPFW1		_MMIO(dev_priv->info.display_mmio_offset + 0x70034)
 #define   DSPFW_SR_SHIFT		23
 #define   DSPFW_SR_MASK			(0x1ff<<23)
 #define   DSPFW_CURSORB_SHIFT		16
@@ -4573,7 +4628,7 @@
 #define   DSPFW_PLANEA_SHIFT		0
 #define   DSPFW_PLANEA_MASK		(0x7f<<0)
 #define   DSPFW_PLANEA_MASK_VLV		(0xff<<0) /* vlv/chv */
-#define DSPFW2			(dev_priv->info.display_mmio_offset + 0x70038)
+#define DSPFW2		_MMIO(dev_priv->info.display_mmio_offset + 0x70038)
 #define   DSPFW_FBC_SR_EN		(1<<31)	  /* g4x */
 #define   DSPFW_FBC_SR_SHIFT		28
 #define   DSPFW_FBC_SR_MASK		(0x7<<28) /* g4x */
@@ -4589,7 +4644,7 @@
 #define   DSPFW_SPRITEA_SHIFT		0
 #define   DSPFW_SPRITEA_MASK		(0x7f<<0) /* g4x */
 #define   DSPFW_SPRITEA_MASK_VLV	(0xff<<0) /* vlv/chv */
-#define DSPFW3			(dev_priv->info.display_mmio_offset + 0x7003c)
+#define DSPFW3		_MMIO(dev_priv->info.display_mmio_offset + 0x7003c)
 #define   DSPFW_HPLL_SR_EN		(1<<31)
 #define   PINEVIEW_SELF_REFRESH_EN	(1<<30)
 #define   DSPFW_CURSOR_SR_SHIFT		24
@@ -4600,14 +4655,14 @@
 #define   DSPFW_HPLL_SR_MASK		(0x1ff<<0)
 
 /* vlv/chv */
-#define DSPFW4			(VLV_DISPLAY_BASE + 0x70070)
+#define DSPFW4		_MMIO(VLV_DISPLAY_BASE + 0x70070)
 #define   DSPFW_SPRITEB_WM1_SHIFT	16
 #define   DSPFW_SPRITEB_WM1_MASK	(0xff<<16)
 #define   DSPFW_CURSORA_WM1_SHIFT	8
 #define   DSPFW_CURSORA_WM1_MASK	(0x3f<<8)
 #define   DSPFW_SPRITEA_WM1_SHIFT	0
 #define   DSPFW_SPRITEA_WM1_MASK	(0xff<<0)
-#define DSPFW5			(VLV_DISPLAY_BASE + 0x70074)
+#define DSPFW5		_MMIO(VLV_DISPLAY_BASE + 0x70074)
 #define   DSPFW_PLANEB_WM1_SHIFT	24
 #define   DSPFW_PLANEB_WM1_MASK		(0xff<<24)
 #define   DSPFW_PLANEA_WM1_SHIFT	16
@@ -4616,11 +4671,11 @@
 #define   DSPFW_CURSORB_WM1_MASK	(0x3f<<8)
 #define   DSPFW_CURSOR_SR_WM1_SHIFT	0
 #define   DSPFW_CURSOR_SR_WM1_MASK	(0x3f<<0)
-#define DSPFW6			(VLV_DISPLAY_BASE + 0x70078)
+#define DSPFW6		_MMIO(VLV_DISPLAY_BASE + 0x70078)
 #define   DSPFW_SR_WM1_SHIFT		0
 #define   DSPFW_SR_WM1_MASK		(0x1ff<<0)
-#define DSPFW7			(VLV_DISPLAY_BASE + 0x7007c)
-#define DSPFW7_CHV		(VLV_DISPLAY_BASE + 0x700b4) /* wtf #1? */
+#define DSPFW7		_MMIO(VLV_DISPLAY_BASE + 0x7007c)
+#define DSPFW7_CHV	_MMIO(VLV_DISPLAY_BASE + 0x700b4) /* wtf #1? */
 #define   DSPFW_SPRITED_WM1_SHIFT	24
 #define   DSPFW_SPRITED_WM1_MASK	(0xff<<24)
 #define   DSPFW_SPRITED_SHIFT		16
@@ -4629,7 +4684,7 @@
 #define   DSPFW_SPRITEC_WM1_MASK	(0xff<<8)
 #define   DSPFW_SPRITEC_SHIFT		0
 #define   DSPFW_SPRITEC_MASK_VLV	(0xff<<0)
-#define DSPFW8_CHV		(VLV_DISPLAY_BASE + 0x700b8)
+#define DSPFW8_CHV	_MMIO(VLV_DISPLAY_BASE + 0x700b8)
 #define   DSPFW_SPRITEF_WM1_SHIFT	24
 #define   DSPFW_SPRITEF_WM1_MASK	(0xff<<24)
 #define   DSPFW_SPRITEF_SHIFT		16
@@ -4638,7 +4693,7 @@
 #define   DSPFW_SPRITEE_WM1_MASK	(0xff<<8)
 #define   DSPFW_SPRITEE_SHIFT		0
 #define   DSPFW_SPRITEE_MASK_VLV	(0xff<<0)
-#define DSPFW9_CHV		(VLV_DISPLAY_BASE + 0x7007c) /* wtf #2? */
+#define DSPFW9_CHV	_MMIO(VLV_DISPLAY_BASE + 0x7007c) /* wtf #2? */
 #define   DSPFW_PLANEC_WM1_SHIFT	24
 #define   DSPFW_PLANEC_WM1_MASK		(0xff<<24)
 #define   DSPFW_PLANEC_SHIFT		16
@@ -4649,7 +4704,7 @@
 #define   DSPFW_CURSORC_MASK		(0x3f<<0)
 
 /* vlv/chv high order bits */
-#define DSPHOWM			(VLV_DISPLAY_BASE + 0x70064)
+#define DSPHOWM		_MMIO(VLV_DISPLAY_BASE + 0x70064)
 #define   DSPFW_SR_HI_SHIFT		24
 #define   DSPFW_SR_HI_MASK		(3<<24) /* 2 bits for chv, 1 for vlv */
 #define   DSPFW_SPRITEF_HI_SHIFT	23
@@ -4670,7 +4725,7 @@
 #define   DSPFW_SPRITEA_HI_MASK		(1<<4)
 #define   DSPFW_PLANEA_HI_SHIFT		0
 #define   DSPFW_PLANEA_HI_MASK		(1<<0)
-#define DSPHOWM1		(VLV_DISPLAY_BASE + 0x70068)
+#define DSPHOWM1	_MMIO(VLV_DISPLAY_BASE + 0x70068)
 #define   DSPFW_SR_WM1_HI_SHIFT		24
 #define   DSPFW_SR_WM1_HI_MASK		(3<<24) /* 2 bits for chv, 1 for vlv */
 #define   DSPFW_SPRITEF_WM1_HI_SHIFT	23
@@ -4693,7 +4748,7 @@
 #define   DSPFW_PLANEA_WM1_HI_MASK	(1<<0)
 
 /* drain latency register values*/
-#define VLV_DDL(pipe)			(VLV_DISPLAY_BASE + 0x70050 + 4 * (pipe))
+#define VLV_DDL(pipe)			_MMIO(VLV_DISPLAY_BASE + 0x70050 + 4 * (pipe))
 #define DDL_CURSOR_SHIFT		24
 #define DDL_SPRITE_SHIFT(sprite)	(8+8*(sprite))
 #define DDL_PLANE_SHIFT			0
@@ -4701,7 +4756,7 @@
 #define DDL_PRECISION_LOW		(0<<7)
 #define DRAIN_LATENCY_MASK		0x7f
 
-#define CBR1_VLV			(VLV_DISPLAY_BASE + 0x70400)
+#define CBR1_VLV			_MMIO(VLV_DISPLAY_BASE + 0x70400)
 #define  CBR_PND_DEADLINE_DISABLE	(1<<31)
 #define  CBR_PWM_CLOCK_MUX_SELECT	(1<<30)
 
@@ -4739,51 +4794,51 @@
 #define I965_CURSOR_DFT_WM	8
 
 /* Watermark register definitions for SKL */
-#define CUR_WM_A_0		0x70140
-#define CUR_WM_B_0		0x71140
-#define PLANE_WM_1_A_0		0x70240
-#define PLANE_WM_1_B_0		0x71240
-#define PLANE_WM_2_A_0		0x70340
-#define PLANE_WM_2_B_0		0x71340
-#define PLANE_WM_TRANS_1_A_0	0x70268
-#define PLANE_WM_TRANS_1_B_0	0x71268
-#define PLANE_WM_TRANS_2_A_0	0x70368
-#define PLANE_WM_TRANS_2_B_0	0x71368
-#define CUR_WM_TRANS_A_0	0x70168
-#define CUR_WM_TRANS_B_0	0x71168
+#define _CUR_WM_A_0		0x70140
+#define _CUR_WM_B_0		0x71140
+#define _PLANE_WM_1_A_0		0x70240
+#define _PLANE_WM_1_B_0		0x71240
+#define _PLANE_WM_2_A_0		0x70340
+#define _PLANE_WM_2_B_0		0x71340
+#define _PLANE_WM_TRANS_1_A_0	0x70268
+#define _PLANE_WM_TRANS_1_B_0	0x71268
+#define _PLANE_WM_TRANS_2_A_0	0x70368
+#define _PLANE_WM_TRANS_2_B_0	0x71368
+#define _CUR_WM_TRANS_A_0	0x70168
+#define _CUR_WM_TRANS_B_0	0x71168
 #define   PLANE_WM_EN		(1 << 31)
 #define   PLANE_WM_LINES_SHIFT	14
 #define   PLANE_WM_LINES_MASK	0x1f
 #define   PLANE_WM_BLOCKS_MASK	0x3ff
 
-#define CUR_WM_0(pipe) _PIPE(pipe, CUR_WM_A_0, CUR_WM_B_0)
-#define CUR_WM(pipe, level) (CUR_WM_0(pipe) + ((4) * (level)))
-#define CUR_WM_TRANS(pipe) _PIPE(pipe, CUR_WM_TRANS_A_0, CUR_WM_TRANS_B_0)
+#define _CUR_WM_0(pipe) _PIPE(pipe, _CUR_WM_A_0, _CUR_WM_B_0)
+#define CUR_WM(pipe, level) _MMIO(_CUR_WM_0(pipe) + ((4) * (level)))
+#define CUR_WM_TRANS(pipe) _MMIO_PIPE(pipe, _CUR_WM_TRANS_A_0, _CUR_WM_TRANS_B_0)
 
-#define _PLANE_WM_1(pipe) _PIPE(pipe, PLANE_WM_1_A_0, PLANE_WM_1_B_0)
-#define _PLANE_WM_2(pipe) _PIPE(pipe, PLANE_WM_2_A_0, PLANE_WM_2_B_0)
+#define _PLANE_WM_1(pipe) _PIPE(pipe, _PLANE_WM_1_A_0, _PLANE_WM_1_B_0)
+#define _PLANE_WM_2(pipe) _PIPE(pipe, _PLANE_WM_2_A_0, _PLANE_WM_2_B_0)
 #define _PLANE_WM_BASE(pipe, plane)	\
 			_PLANE(plane, _PLANE_WM_1(pipe), _PLANE_WM_2(pipe))
 #define PLANE_WM(pipe, plane, level)	\
-			(_PLANE_WM_BASE(pipe, plane) + ((4) * (level)))
+			_MMIO(_PLANE_WM_BASE(pipe, plane) + ((4) * (level)))
 #define _PLANE_WM_TRANS_1(pipe)	\
-			_PIPE(pipe, PLANE_WM_TRANS_1_A_0, PLANE_WM_TRANS_1_B_0)
+			_PIPE(pipe, _PLANE_WM_TRANS_1_A_0, _PLANE_WM_TRANS_1_B_0)
 #define _PLANE_WM_TRANS_2(pipe)	\
-			_PIPE(pipe, PLANE_WM_TRANS_2_A_0, PLANE_WM_TRANS_2_B_0)
+			_PIPE(pipe, _PLANE_WM_TRANS_2_A_0, _PLANE_WM_TRANS_2_B_0)
 #define PLANE_WM_TRANS(pipe, plane)	\
-		_PLANE(plane, _PLANE_WM_TRANS_1(pipe), _PLANE_WM_TRANS_2(pipe))
+	_MMIO(_PLANE(plane, _PLANE_WM_TRANS_1(pipe), _PLANE_WM_TRANS_2(pipe)))
 
 /* define the Watermark register on Ironlake */
-#define WM0_PIPEA_ILK		0x45100
+#define WM0_PIPEA_ILK		_MMIO(0x45100)
 #define  WM0_PIPE_PLANE_MASK	(0xffff<<16)
 #define  WM0_PIPE_PLANE_SHIFT	16
 #define  WM0_PIPE_SPRITE_MASK	(0xff<<8)
 #define  WM0_PIPE_SPRITE_SHIFT	8
 #define  WM0_PIPE_CURSOR_MASK	(0xff)
 
-#define WM0_PIPEB_ILK		0x45104
-#define WM0_PIPEC_IVB		0x45200
-#define WM1_LP_ILK		0x45108
+#define WM0_PIPEB_ILK		_MMIO(0x45104)
+#define WM0_PIPEC_IVB		_MMIO(0x45200)
+#define WM1_LP_ILK		_MMIO(0x45108)
 #define  WM1_LP_SR_EN		(1<<31)
 #define  WM1_LP_LATENCY_SHIFT	24
 #define  WM1_LP_LATENCY_MASK	(0x7f<<24)
@@ -4793,13 +4848,13 @@
 #define  WM1_LP_SR_MASK		(0x7ff<<8)
 #define  WM1_LP_SR_SHIFT	8
 #define  WM1_LP_CURSOR_MASK	(0xff)
-#define WM2_LP_ILK		0x4510c
+#define WM2_LP_ILK		_MMIO(0x4510c)
 #define  WM2_LP_EN		(1<<31)
-#define WM3_LP_ILK		0x45110
+#define WM3_LP_ILK		_MMIO(0x45110)
 #define  WM3_LP_EN		(1<<31)
-#define WM1S_LP_ILK		0x45120
-#define WM2S_LP_IVB		0x45124
-#define WM3S_LP_IVB		0x45128
+#define WM1S_LP_ILK		_MMIO(0x45120)
+#define WM2S_LP_IVB		_MMIO(0x45124)
+#define WM3S_LP_IVB		_MMIO(0x45128)
 #define  WM1S_LP_EN		(1<<31)
 
 #define HSW_WM_LP_VAL(lat, fbc, pri, cur) \
@@ -4807,7 +4862,7 @@
 	 ((fbc) << WM1_LP_FBC_SHIFT) | ((pri) << WM1_LP_SR_SHIFT) | (cur))
 
 /* Memory latency timer register */
-#define MLTR_ILK		0x11222
+#define MLTR_ILK		_MMIO(0x11222)
 #define  MLTR_WM1_SHIFT		0
 #define  MLTR_WM2_SHIFT		8
 /* the unit of memory self-refresh latency time is 0.5us */
@@ -4815,7 +4870,7 @@
 
 
 /* the address where we get all kinds of latency value */
-#define SSKPD			0x5d10
+#define SSKPD			_MMIO(0x5d10)
 #define SSKPD_WM_MASK		0x3f
 #define SSKPD_WM0_SHIFT		0
 #define SSKPD_WM1_SHIFT		8
@@ -4848,8 +4903,8 @@
 /* GM45+ just has to be different */
 #define _PIPEA_FRMCOUNT_G4X	0x70040
 #define _PIPEA_FLIPCOUNT_G4X	0x70044
-#define PIPE_FRMCOUNT_G4X(pipe) _PIPE2(pipe, _PIPEA_FRMCOUNT_G4X)
-#define PIPE_FLIPCOUNT_G4X(pipe) _PIPE2(pipe, _PIPEA_FLIPCOUNT_G4X)
+#define PIPE_FRMCOUNT_G4X(pipe) _MMIO_PIPE2(pipe, _PIPEA_FRMCOUNT_G4X)
+#define PIPE_FLIPCOUNT_G4X(pipe) _MMIO_PIPE2(pipe, _PIPEA_FLIPCOUNT_G4X)
 
 /* Cursor A & B regs */
 #define _CURACNTR		0x70080
@@ -4887,7 +4942,7 @@
 #define   CURSOR_POS_SIGN       0x8000
 #define   CURSOR_X_SHIFT        0
 #define   CURSOR_Y_SHIFT        16
-#define CURSIZE			0x700a0
+#define CURSIZE			_MMIO(0x700a0)
 #define _CURBCNTR		0x700c0
 #define _CURBBASE		0x700c4
 #define _CURBPOS		0x700c8
@@ -4896,7 +4951,7 @@
 #define _CURBBASE_IVB		0x71084
 #define _CURBPOS_IVB		0x71088
 
-#define _CURSOR2(pipe, reg) (dev_priv->info.cursor_offsets[(pipe)] - \
+#define _CURSOR2(pipe, reg) _MMIO(dev_priv->info.cursor_offsets[(pipe)] - \
 	dev_priv->info.cursor_offsets[PIPE_A] + (reg) + \
 	dev_priv->info.display_mmio_offset)
 
@@ -4957,16 +5012,16 @@
 #define _DSPAOFFSET				0x701A4 /* HSW */
 #define _DSPASURFLIVE				0x701AC
 
-#define DSPCNTR(plane) _PIPE2(plane, _DSPACNTR)
-#define DSPADDR(plane) _PIPE2(plane, _DSPAADDR)
-#define DSPSTRIDE(plane) _PIPE2(plane, _DSPASTRIDE)
-#define DSPPOS(plane) _PIPE2(plane, _DSPAPOS)
-#define DSPSIZE(plane) _PIPE2(plane, _DSPASIZE)
-#define DSPSURF(plane) _PIPE2(plane, _DSPASURF)
-#define DSPTILEOFF(plane) _PIPE2(plane, _DSPATILEOFF)
-#define DSPLINOFF(plane) DSPADDR(plane)
-#define DSPOFFSET(plane) _PIPE2(plane, _DSPAOFFSET)
-#define DSPSURFLIVE(plane) _PIPE2(plane, _DSPASURFLIVE)
+#define DSPCNTR(plane)		_MMIO_PIPE2(plane, _DSPACNTR)
+#define DSPADDR(plane)		_MMIO_PIPE2(plane, _DSPAADDR)
+#define DSPSTRIDE(plane)	_MMIO_PIPE2(plane, _DSPASTRIDE)
+#define DSPPOS(plane)		_MMIO_PIPE2(plane, _DSPAPOS)
+#define DSPSIZE(plane)		_MMIO_PIPE2(plane, _DSPASIZE)
+#define DSPSURF(plane)		_MMIO_PIPE2(plane, _DSPASURF)
+#define DSPTILEOFF(plane)	_MMIO_PIPE2(plane, _DSPATILEOFF)
+#define DSPLINOFF(plane)	DSPADDR(plane)
+#define DSPOFFSET(plane)	_MMIO_PIPE2(plane, _DSPAOFFSET)
+#define DSPSURFLIVE(plane)	_MMIO_PIPE2(plane, _DSPASURFLIVE)
 
 /* CHV pipe B blender and primary plane */
 #define _CHV_BLEND_A		0x60a00
@@ -4980,11 +5035,11 @@
 #define _PRIMCNSTALPHA_A	0x60a10
 #define   PRIM_CONST_ALPHA_ENABLE	(1<<31)
 
-#define CHV_BLEND(pipe) _TRANSCODER2(pipe, _CHV_BLEND_A)
-#define CHV_CANVAS(pipe) _TRANSCODER2(pipe, _CHV_CANVAS_A)
-#define PRIMPOS(plane) _TRANSCODER2(plane, _PRIMPOS_A)
-#define PRIMSIZE(plane) _TRANSCODER2(plane, _PRIMSIZE_A)
-#define PRIMCNSTALPHA(plane) _TRANSCODER2(plane, _PRIMCNSTALPHA_A)
+#define CHV_BLEND(pipe)		_MMIO_TRANS2(pipe, _CHV_BLEND_A)
+#define CHV_CANVAS(pipe)	_MMIO_TRANS2(pipe, _CHV_CANVAS_A)
+#define PRIMPOS(plane)		_MMIO_TRANS2(plane, _PRIMPOS_A)
+#define PRIMSIZE(plane)		_MMIO_TRANS2(plane, _PRIMSIZE_A)
+#define PRIMCNSTALPHA(plane)	_MMIO_TRANS2(plane, _PRIMCNSTALPHA_A)
 
 /* Display/Sprite base address macros */
 #define DISP_BASEADDR_MASK	(0xfffff000)
@@ -5002,9 +5057,10 @@
  * [10:1f] all
  * [30:32] all
  */
-#define SWF0(i)	(dev_priv->info.display_mmio_offset + 0x70410 + (i) * 4)
-#define SWF1(i)	(dev_priv->info.display_mmio_offset + 0x71410 + (i) * 4)
-#define SWF3(i)	(dev_priv->info.display_mmio_offset + 0x72414 + (i) * 4)
+#define SWF0(i)	_MMIO(dev_priv->info.display_mmio_offset + 0x70410 + (i) * 4)
+#define SWF1(i)	_MMIO(dev_priv->info.display_mmio_offset + 0x71410 + (i) * 4)
+#define SWF3(i)	_MMIO(dev_priv->info.display_mmio_offset + 0x72414 + (i) * 4)
+#define SWF_ILK(i)	_MMIO(0x4F000 + (i) * 4)
 
 /* Pipe B */
 #define _PIPEBDSL		(dev_priv->info.display_mmio_offset + 0x71000)
@@ -5086,18 +5142,18 @@
 #define _DVSBSCALE		0x73204
 #define _DVSBGAMC		0x73300
 
-#define DVSCNTR(pipe) _PIPE(pipe, _DVSACNTR, _DVSBCNTR)
-#define DVSLINOFF(pipe) _PIPE(pipe, _DVSALINOFF, _DVSBLINOFF)
-#define DVSSTRIDE(pipe) _PIPE(pipe, _DVSASTRIDE, _DVSBSTRIDE)
-#define DVSPOS(pipe) _PIPE(pipe, _DVSAPOS, _DVSBPOS)
-#define DVSSURF(pipe) _PIPE(pipe, _DVSASURF, _DVSBSURF)
-#define DVSKEYMAX(pipe) _PIPE(pipe, _DVSAKEYMAXVAL, _DVSBKEYMAXVAL)
-#define DVSSIZE(pipe) _PIPE(pipe, _DVSASIZE, _DVSBSIZE)
-#define DVSSCALE(pipe) _PIPE(pipe, _DVSASCALE, _DVSBSCALE)
-#define DVSTILEOFF(pipe) _PIPE(pipe, _DVSATILEOFF, _DVSBTILEOFF)
-#define DVSKEYVAL(pipe) _PIPE(pipe, _DVSAKEYVAL, _DVSBKEYVAL)
-#define DVSKEYMSK(pipe) _PIPE(pipe, _DVSAKEYMSK, _DVSBKEYMSK)
-#define DVSSURFLIVE(pipe) _PIPE(pipe, _DVSASURFLIVE, _DVSBSURFLIVE)
+#define DVSCNTR(pipe) _MMIO_PIPE(pipe, _DVSACNTR, _DVSBCNTR)
+#define DVSLINOFF(pipe) _MMIO_PIPE(pipe, _DVSALINOFF, _DVSBLINOFF)
+#define DVSSTRIDE(pipe) _MMIO_PIPE(pipe, _DVSASTRIDE, _DVSBSTRIDE)
+#define DVSPOS(pipe) _MMIO_PIPE(pipe, _DVSAPOS, _DVSBPOS)
+#define DVSSURF(pipe) _MMIO_PIPE(pipe, _DVSASURF, _DVSBSURF)
+#define DVSKEYMAX(pipe) _MMIO_PIPE(pipe, _DVSAKEYMAXVAL, _DVSBKEYMAXVAL)
+#define DVSSIZE(pipe) _MMIO_PIPE(pipe, _DVSASIZE, _DVSBSIZE)
+#define DVSSCALE(pipe) _MMIO_PIPE(pipe, _DVSASCALE, _DVSBSCALE)
+#define DVSTILEOFF(pipe) _MMIO_PIPE(pipe, _DVSATILEOFF, _DVSBTILEOFF)
+#define DVSKEYVAL(pipe) _MMIO_PIPE(pipe, _DVSAKEYVAL, _DVSBKEYVAL)
+#define DVSKEYMSK(pipe) _MMIO_PIPE(pipe, _DVSAKEYMSK, _DVSBKEYMSK)
+#define DVSSURFLIVE(pipe) _MMIO_PIPE(pipe, _DVSASURFLIVE, _DVSBSURFLIVE)
 
 #define _SPRA_CTL		0x70280
 #define   SPRITE_ENABLE			(1<<31)
@@ -5160,20 +5216,20 @@
 #define _SPRB_SCALE		0x71304
 #define _SPRB_GAMC		0x71400
 
-#define SPRCTL(pipe) _PIPE(pipe, _SPRA_CTL, _SPRB_CTL)
-#define SPRLINOFF(pipe) _PIPE(pipe, _SPRA_LINOFF, _SPRB_LINOFF)
-#define SPRSTRIDE(pipe) _PIPE(pipe, _SPRA_STRIDE, _SPRB_STRIDE)
-#define SPRPOS(pipe) _PIPE(pipe, _SPRA_POS, _SPRB_POS)
-#define SPRSIZE(pipe) _PIPE(pipe, _SPRA_SIZE, _SPRB_SIZE)
-#define SPRKEYVAL(pipe) _PIPE(pipe, _SPRA_KEYVAL, _SPRB_KEYVAL)
-#define SPRKEYMSK(pipe) _PIPE(pipe, _SPRA_KEYMSK, _SPRB_KEYMSK)
-#define SPRSURF(pipe) _PIPE(pipe, _SPRA_SURF, _SPRB_SURF)
-#define SPRKEYMAX(pipe) _PIPE(pipe, _SPRA_KEYMAX, _SPRB_KEYMAX)
-#define SPRTILEOFF(pipe) _PIPE(pipe, _SPRA_TILEOFF, _SPRB_TILEOFF)
-#define SPROFFSET(pipe) _PIPE(pipe, _SPRA_OFFSET, _SPRB_OFFSET)
-#define SPRSCALE(pipe) _PIPE(pipe, _SPRA_SCALE, _SPRB_SCALE)
-#define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC)
-#define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE)
+#define SPRCTL(pipe) _MMIO_PIPE(pipe, _SPRA_CTL, _SPRB_CTL)
+#define SPRLINOFF(pipe) _MMIO_PIPE(pipe, _SPRA_LINOFF, _SPRB_LINOFF)
+#define SPRSTRIDE(pipe) _MMIO_PIPE(pipe, _SPRA_STRIDE, _SPRB_STRIDE)
+#define SPRPOS(pipe) _MMIO_PIPE(pipe, _SPRA_POS, _SPRB_POS)
+#define SPRSIZE(pipe) _MMIO_PIPE(pipe, _SPRA_SIZE, _SPRB_SIZE)
+#define SPRKEYVAL(pipe) _MMIO_PIPE(pipe, _SPRA_KEYVAL, _SPRB_KEYVAL)
+#define SPRKEYMSK(pipe) _MMIO_PIPE(pipe, _SPRA_KEYMSK, _SPRB_KEYMSK)
+#define SPRSURF(pipe) _MMIO_PIPE(pipe, _SPRA_SURF, _SPRB_SURF)
+#define SPRKEYMAX(pipe) _MMIO_PIPE(pipe, _SPRA_KEYMAX, _SPRB_KEYMAX)
+#define SPRTILEOFF(pipe) _MMIO_PIPE(pipe, _SPRA_TILEOFF, _SPRB_TILEOFF)
+#define SPROFFSET(pipe) _MMIO_PIPE(pipe, _SPRA_OFFSET, _SPRB_OFFSET)
+#define SPRSCALE(pipe) _MMIO_PIPE(pipe, _SPRA_SCALE, _SPRB_SCALE)
+#define SPRGAMC(pipe) _MMIO_PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC)
+#define SPRSURFLIVE(pipe) _MMIO_PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE)
 
 #define _SPACNTR		(VLV_DISPLAY_BASE + 0x72180)
 #define   SP_ENABLE			(1<<31)
@@ -5223,18 +5279,18 @@
 #define _SPBCONSTALPHA		(VLV_DISPLAY_BASE + 0x722a8)
 #define _SPBGAMC		(VLV_DISPLAY_BASE + 0x722f4)
 
-#define SPCNTR(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPACNTR, _SPBCNTR)
-#define SPLINOFF(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPALINOFF, _SPBLINOFF)
-#define SPSTRIDE(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPASTRIDE, _SPBSTRIDE)
-#define SPPOS(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAPOS, _SPBPOS)
-#define SPSIZE(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPASIZE, _SPBSIZE)
-#define SPKEYMINVAL(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAKEYMINVAL, _SPBKEYMINVAL)
-#define SPKEYMSK(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAKEYMSK, _SPBKEYMSK)
-#define SPSURF(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPASURF, _SPBSURF)
-#define SPKEYMAXVAL(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAKEYMAXVAL, _SPBKEYMAXVAL)
-#define SPTILEOFF(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPATILEOFF, _SPBTILEOFF)
-#define SPCONSTALPHA(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPACONSTALPHA, _SPBCONSTALPHA)
-#define SPGAMC(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAGAMC, _SPBGAMC)
+#define SPCNTR(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPACNTR, _SPBCNTR)
+#define SPLINOFF(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPALINOFF, _SPBLINOFF)
+#define SPSTRIDE(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPASTRIDE, _SPBSTRIDE)
+#define SPPOS(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPAPOS, _SPBPOS)
+#define SPSIZE(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPASIZE, _SPBSIZE)
+#define SPKEYMINVAL(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPAKEYMINVAL, _SPBKEYMINVAL)
+#define SPKEYMSK(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPAKEYMSK, _SPBKEYMSK)
+#define SPSURF(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPASURF, _SPBSURF)
+#define SPKEYMAXVAL(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPAKEYMAXVAL, _SPBKEYMAXVAL)
+#define SPTILEOFF(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPATILEOFF, _SPBTILEOFF)
+#define SPCONSTALPHA(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPACONSTALPHA, _SPBCONSTALPHA)
+#define SPGAMC(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPAGAMC, _SPBGAMC)
 
 /*
  * CHV pipe B sprite CSC
@@ -5243,29 +5299,29 @@
  * |yg| = |c3 c4 c5| x |yg + yg_ioff| + |yg_ooff|
  * |cb|   |c6 c7 c8|   |cb + cr_ioff|   |cb_ooff|
  */
-#define SPCSCYGOFF(sprite)	(VLV_DISPLAY_BASE + 0x6d900 + (sprite) * 0x1000)
-#define SPCSCCBOFF(sprite)	(VLV_DISPLAY_BASE + 0x6d904 + (sprite) * 0x1000)
-#define SPCSCCROFF(sprite)	(VLV_DISPLAY_BASE + 0x6d908 + (sprite) * 0x1000)
+#define SPCSCYGOFF(sprite)	_MMIO(VLV_DISPLAY_BASE + 0x6d900 + (sprite) * 0x1000)
+#define SPCSCCBOFF(sprite)	_MMIO(VLV_DISPLAY_BASE + 0x6d904 + (sprite) * 0x1000)
+#define SPCSCCROFF(sprite)	_MMIO(VLV_DISPLAY_BASE + 0x6d908 + (sprite) * 0x1000)
 #define  SPCSC_OOFF(x)		(((x) & 0x7ff) << 16) /* s11 */
 #define  SPCSC_IOFF(x)		(((x) & 0x7ff) << 0) /* s11 */
 
-#define SPCSCC01(sprite)	(VLV_DISPLAY_BASE + 0x6d90c + (sprite) * 0x1000)
-#define SPCSCC23(sprite)	(VLV_DISPLAY_BASE + 0x6d910 + (sprite) * 0x1000)
-#define SPCSCC45(sprite)	(VLV_DISPLAY_BASE + 0x6d914 + (sprite) * 0x1000)
-#define SPCSCC67(sprite)	(VLV_DISPLAY_BASE + 0x6d918 + (sprite) * 0x1000)
-#define SPCSCC8(sprite)		(VLV_DISPLAY_BASE + 0x6d91c + (sprite) * 0x1000)
+#define SPCSCC01(sprite)	_MMIO(VLV_DISPLAY_BASE + 0x6d90c + (sprite) * 0x1000)
+#define SPCSCC23(sprite)	_MMIO(VLV_DISPLAY_BASE + 0x6d910 + (sprite) * 0x1000)
+#define SPCSCC45(sprite)	_MMIO(VLV_DISPLAY_BASE + 0x6d914 + (sprite) * 0x1000)
+#define SPCSCC67(sprite)	_MMIO(VLV_DISPLAY_BASE + 0x6d918 + (sprite) * 0x1000)
+#define SPCSCC8(sprite)		_MMIO(VLV_DISPLAY_BASE + 0x6d91c + (sprite) * 0x1000)
 #define  SPCSC_C1(x)		(((x) & 0x7fff) << 16) /* s3.12 */
 #define  SPCSC_C0(x)		(((x) & 0x7fff) << 0) /* s3.12 */
 
-#define SPCSCYGICLAMP(sprite)	(VLV_DISPLAY_BASE + 0x6d920 + (sprite) * 0x1000)
-#define SPCSCCBICLAMP(sprite)	(VLV_DISPLAY_BASE + 0x6d924 + (sprite) * 0x1000)
-#define SPCSCCRICLAMP(sprite)	(VLV_DISPLAY_BASE + 0x6d928 + (sprite) * 0x1000)
+#define SPCSCYGICLAMP(sprite)	_MMIO(VLV_DISPLAY_BASE + 0x6d920 + (sprite) * 0x1000)
+#define SPCSCCBICLAMP(sprite)	_MMIO(VLV_DISPLAY_BASE + 0x6d924 + (sprite) * 0x1000)
+#define SPCSCCRICLAMP(sprite)	_MMIO(VLV_DISPLAY_BASE + 0x6d928 + (sprite) * 0x1000)
 #define  SPCSC_IMAX(x)		(((x) & 0x7ff) << 16) /* s11 */
 #define  SPCSC_IMIN(x)		(((x) & 0x7ff) << 0) /* s11 */
 
-#define SPCSCYGOCLAMP(sprite)	(VLV_DISPLAY_BASE + 0x6d92c + (sprite) * 0x1000)
-#define SPCSCCBOCLAMP(sprite)	(VLV_DISPLAY_BASE + 0x6d930 + (sprite) * 0x1000)
-#define SPCSCCROCLAMP(sprite)	(VLV_DISPLAY_BASE + 0x6d934 + (sprite) * 0x1000)
+#define SPCSCYGOCLAMP(sprite)	_MMIO(VLV_DISPLAY_BASE + 0x6d92c + (sprite) * 0x1000)
+#define SPCSCCBOCLAMP(sprite)	_MMIO(VLV_DISPLAY_BASE + 0x6d930 + (sprite) * 0x1000)
+#define SPCSCCROCLAMP(sprite)	_MMIO(VLV_DISPLAY_BASE + 0x6d934 + (sprite) * 0x1000)
 #define  SPCSC_OMAX(x)		((x) << 16) /* u10 */
 #define  SPCSC_OMIN(x)		((x) << 0) /* u10 */
 
@@ -5346,7 +5402,7 @@
 #define _PLANE_CTL_2(pipe)	_PIPE(pipe, _PLANE_CTL_2_A, _PLANE_CTL_2_B)
 #define _PLANE_CTL_3(pipe)	_PIPE(pipe, _PLANE_CTL_3_A, _PLANE_CTL_3_B)
 #define PLANE_CTL(pipe, plane)	\
-	_PLANE(plane, _PLANE_CTL_1(pipe), _PLANE_CTL_2(pipe))
+	_MMIO_PLANE(plane, _PLANE_CTL_1(pipe), _PLANE_CTL_2(pipe))
 
 #define _PLANE_STRIDE_1_B			0x71188
 #define _PLANE_STRIDE_2_B			0x71288
@@ -5358,7 +5414,7 @@
 #define _PLANE_STRIDE_3(pipe)	\
 	_PIPE(pipe, _PLANE_STRIDE_3_A, _PLANE_STRIDE_3_B)
 #define PLANE_STRIDE(pipe, plane)	\
-	_PLANE(plane, _PLANE_STRIDE_1(pipe), _PLANE_STRIDE_2(pipe))
+	_MMIO_PLANE(plane, _PLANE_STRIDE_1(pipe), _PLANE_STRIDE_2(pipe))
 
 #define _PLANE_POS_1_B				0x7118c
 #define _PLANE_POS_2_B				0x7128c
@@ -5367,7 +5423,7 @@
 #define _PLANE_POS_2(pipe)	_PIPE(pipe, _PLANE_POS_2_A, _PLANE_POS_2_B)
 #define _PLANE_POS_3(pipe)	_PIPE(pipe, _PLANE_POS_3_A, _PLANE_POS_3_B)
 #define PLANE_POS(pipe, plane)	\
-	_PLANE(plane, _PLANE_POS_1(pipe), _PLANE_POS_2(pipe))
+	_MMIO_PLANE(plane, _PLANE_POS_1(pipe), _PLANE_POS_2(pipe))
 
 #define _PLANE_SIZE_1_B				0x71190
 #define _PLANE_SIZE_2_B				0x71290
@@ -5376,7 +5432,7 @@
 #define _PLANE_SIZE_2(pipe)	_PIPE(pipe, _PLANE_SIZE_2_A, _PLANE_SIZE_2_B)
 #define _PLANE_SIZE_3(pipe)	_PIPE(pipe, _PLANE_SIZE_3_A, _PLANE_SIZE_3_B)
 #define PLANE_SIZE(pipe, plane)	\
-	_PLANE(plane, _PLANE_SIZE_1(pipe), _PLANE_SIZE_2(pipe))
+	_MMIO_PLANE(plane, _PLANE_SIZE_1(pipe), _PLANE_SIZE_2(pipe))
 
 #define _PLANE_SURF_1_B				0x7119c
 #define _PLANE_SURF_2_B				0x7129c
@@ -5385,35 +5441,35 @@
 #define _PLANE_SURF_2(pipe)	_PIPE(pipe, _PLANE_SURF_2_A, _PLANE_SURF_2_B)
 #define _PLANE_SURF_3(pipe)	_PIPE(pipe, _PLANE_SURF_3_A, _PLANE_SURF_3_B)
 #define PLANE_SURF(pipe, plane)	\
-	_PLANE(plane, _PLANE_SURF_1(pipe), _PLANE_SURF_2(pipe))
+	_MMIO_PLANE(plane, _PLANE_SURF_1(pipe), _PLANE_SURF_2(pipe))
 
 #define _PLANE_OFFSET_1_B			0x711a4
 #define _PLANE_OFFSET_2_B			0x712a4
 #define _PLANE_OFFSET_1(pipe) _PIPE(pipe, _PLANE_OFFSET_1_A, _PLANE_OFFSET_1_B)
 #define _PLANE_OFFSET_2(pipe) _PIPE(pipe, _PLANE_OFFSET_2_A, _PLANE_OFFSET_2_B)
 #define PLANE_OFFSET(pipe, plane)	\
-	_PLANE(plane, _PLANE_OFFSET_1(pipe), _PLANE_OFFSET_2(pipe))
+	_MMIO_PLANE(plane, _PLANE_OFFSET_1(pipe), _PLANE_OFFSET_2(pipe))
 
 #define _PLANE_KEYVAL_1_B			0x71194
 #define _PLANE_KEYVAL_2_B			0x71294
 #define _PLANE_KEYVAL_1(pipe) _PIPE(pipe, _PLANE_KEYVAL_1_A, _PLANE_KEYVAL_1_B)
 #define _PLANE_KEYVAL_2(pipe) _PIPE(pipe, _PLANE_KEYVAL_2_A, _PLANE_KEYVAL_2_B)
 #define PLANE_KEYVAL(pipe, plane)	\
-	_PLANE(plane, _PLANE_KEYVAL_1(pipe), _PLANE_KEYVAL_2(pipe))
+	_MMIO_PLANE(plane, _PLANE_KEYVAL_1(pipe), _PLANE_KEYVAL_2(pipe))
 
 #define _PLANE_KEYMSK_1_B			0x71198
 #define _PLANE_KEYMSK_2_B			0x71298
 #define _PLANE_KEYMSK_1(pipe) _PIPE(pipe, _PLANE_KEYMSK_1_A, _PLANE_KEYMSK_1_B)
 #define _PLANE_KEYMSK_2(pipe) _PIPE(pipe, _PLANE_KEYMSK_2_A, _PLANE_KEYMSK_2_B)
 #define PLANE_KEYMSK(pipe, plane)	\
-	_PLANE(plane, _PLANE_KEYMSK_1(pipe), _PLANE_KEYMSK_2(pipe))
+	_MMIO_PLANE(plane, _PLANE_KEYMSK_1(pipe), _PLANE_KEYMSK_2(pipe))
 
 #define _PLANE_KEYMAX_1_B			0x711a0
 #define _PLANE_KEYMAX_2_B			0x712a0
 #define _PLANE_KEYMAX_1(pipe) _PIPE(pipe, _PLANE_KEYMAX_1_A, _PLANE_KEYMAX_1_B)
 #define _PLANE_KEYMAX_2(pipe) _PIPE(pipe, _PLANE_KEYMAX_2_A, _PLANE_KEYMAX_2_B)
 #define PLANE_KEYMAX(pipe, plane)	\
-	_PLANE(plane, _PLANE_KEYMAX_1(pipe), _PLANE_KEYMAX_2(pipe))
+	_MMIO_PLANE(plane, _PLANE_KEYMAX_1(pipe), _PLANE_KEYMAX_2(pipe))
 
 #define _PLANE_BUF_CFG_1_B			0x7127c
 #define _PLANE_BUF_CFG_2_B			0x7137c
@@ -5422,7 +5478,7 @@
 #define _PLANE_BUF_CFG_2(pipe)	\
 	_PIPE(pipe, _PLANE_BUF_CFG_2_A, _PLANE_BUF_CFG_2_B)
 #define PLANE_BUF_CFG(pipe, plane)	\
-	_PLANE(plane, _PLANE_BUF_CFG_1(pipe), _PLANE_BUF_CFG_2(pipe))
+	_MMIO_PLANE(plane, _PLANE_BUF_CFG_1(pipe), _PLANE_BUF_CFG_2(pipe))
 
 #define _PLANE_NV12_BUF_CFG_1_B		0x71278
 #define _PLANE_NV12_BUF_CFG_2_B		0x71378
@@ -5431,26 +5487,26 @@
 #define _PLANE_NV12_BUF_CFG_2(pipe)	\
 	_PIPE(pipe, _PLANE_NV12_BUF_CFG_2_A, _PLANE_NV12_BUF_CFG_2_B)
 #define PLANE_NV12_BUF_CFG(pipe, plane)	\
-	_PLANE(plane, _PLANE_NV12_BUF_CFG_1(pipe), _PLANE_NV12_BUF_CFG_2(pipe))
+	_MMIO_PLANE(plane, _PLANE_NV12_BUF_CFG_1(pipe), _PLANE_NV12_BUF_CFG_2(pipe))
 
 /* SKL new cursor registers */
 #define _CUR_BUF_CFG_A				0x7017c
 #define _CUR_BUF_CFG_B				0x7117c
-#define CUR_BUF_CFG(pipe)	_PIPE(pipe, _CUR_BUF_CFG_A, _CUR_BUF_CFG_B)
+#define CUR_BUF_CFG(pipe)	_MMIO_PIPE(pipe, _CUR_BUF_CFG_A, _CUR_BUF_CFG_B)
 
 /* VBIOS regs */
-#define VGACNTRL		0x71400
+#define VGACNTRL		_MMIO(0x71400)
 # define VGA_DISP_DISABLE			(1 << 31)
 # define VGA_2X_MODE				(1 << 30)
 # define VGA_PIPE_B_SELECT			(1 << 29)
 
-#define VLV_VGACNTRL		(VLV_DISPLAY_BASE + 0x71400)
+#define VLV_VGACNTRL		_MMIO(VLV_DISPLAY_BASE + 0x71400)
 
 /* Ironlake */
 
-#define CPU_VGACNTRL	0x41000
+#define CPU_VGACNTRL	_MMIO(0x41000)
 
-#define DIGITAL_PORT_HOTPLUG_CNTRL	0x44030
+#define DIGITAL_PORT_HOTPLUG_CNTRL	_MMIO(0x44030)
 #define  DIGITAL_PORTA_HOTPLUG_ENABLE		(1 << 4)
 #define  DIGITAL_PORTA_PULSE_DURATION_2ms	(0 << 2) /* pre-HSW */
 #define  DIGITAL_PORTA_PULSE_DURATION_4_5ms	(1 << 2) /* pre-HSW */
@@ -5463,26 +5519,26 @@
 #define  DIGITAL_PORTA_HOTPLUG_LONG_DETECT	(2 << 0)
 
 /* refresh rate hardware control */
-#define RR_HW_CTL       0x45300
+#define RR_HW_CTL       _MMIO(0x45300)
 #define  RR_HW_LOW_POWER_FRAMES_MASK    0xff
 #define  RR_HW_HIGH_POWER_FRAMES_MASK   0xff00
 
-#define FDI_PLL_BIOS_0  0x46000
+#define FDI_PLL_BIOS_0  _MMIO(0x46000)
 #define  FDI_PLL_FB_CLOCK_MASK  0xff
-#define FDI_PLL_BIOS_1  0x46004
-#define FDI_PLL_BIOS_2  0x46008
-#define DISPLAY_PORT_PLL_BIOS_0         0x4600c
-#define DISPLAY_PORT_PLL_BIOS_1         0x46010
-#define DISPLAY_PORT_PLL_BIOS_2         0x46014
+#define FDI_PLL_BIOS_1  _MMIO(0x46004)
+#define FDI_PLL_BIOS_2  _MMIO(0x46008)
+#define DISPLAY_PORT_PLL_BIOS_0         _MMIO(0x4600c)
+#define DISPLAY_PORT_PLL_BIOS_1         _MMIO(0x46010)
+#define DISPLAY_PORT_PLL_BIOS_2         _MMIO(0x46014)
 
-#define PCH_3DCGDIS0		0x46020
+#define PCH_3DCGDIS0		_MMIO(0x46020)
 # define MARIUNIT_CLOCK_GATE_DISABLE		(1 << 18)
 # define SVSMUNIT_CLOCK_GATE_DISABLE		(1 << 1)
 
-#define PCH_3DCGDIS1		0x46024
+#define PCH_3DCGDIS1		_MMIO(0x46024)
 # define VFMUNIT_CLOCK_GATE_DISABLE		(1 << 11)
 
-#define FDI_PLL_FREQ_CTL        0x46030
+#define FDI_PLL_FREQ_CTL        _MMIO(0x46030)
 #define  FDI_PLL_FREQ_CHANGE_REQUEST    (1<<24)
 #define  FDI_PLL_FREQ_LOCK_LIMIT_MASK   0xfff00
 #define  FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK  0xff
@@ -5519,14 +5575,14 @@
 #define _PIPEB_LINK_M2		0x61048
 #define _PIPEB_LINK_N2		0x6104c
 
-#define PIPE_DATA_M1(tran) _TRANSCODER2(tran, _PIPEA_DATA_M1)
-#define PIPE_DATA_N1(tran) _TRANSCODER2(tran, _PIPEA_DATA_N1)
-#define PIPE_DATA_M2(tran) _TRANSCODER2(tran, _PIPEA_DATA_M2)
-#define PIPE_DATA_N2(tran) _TRANSCODER2(tran, _PIPEA_DATA_N2)
-#define PIPE_LINK_M1(tran) _TRANSCODER2(tran, _PIPEA_LINK_M1)
-#define PIPE_LINK_N1(tran) _TRANSCODER2(tran, _PIPEA_LINK_N1)
-#define PIPE_LINK_M2(tran) _TRANSCODER2(tran, _PIPEA_LINK_M2)
-#define PIPE_LINK_N2(tran) _TRANSCODER2(tran, _PIPEA_LINK_N2)
+#define PIPE_DATA_M1(tran) _MMIO_TRANS2(tran, _PIPEA_DATA_M1)
+#define PIPE_DATA_N1(tran) _MMIO_TRANS2(tran, _PIPEA_DATA_N1)
+#define PIPE_DATA_M2(tran) _MMIO_TRANS2(tran, _PIPEA_DATA_M2)
+#define PIPE_DATA_N2(tran) _MMIO_TRANS2(tran, _PIPEA_DATA_N2)
+#define PIPE_LINK_M1(tran) _MMIO_TRANS2(tran, _PIPEA_LINK_M1)
+#define PIPE_LINK_N1(tran) _MMIO_TRANS2(tran, _PIPEA_LINK_N1)
+#define PIPE_LINK_M2(tran) _MMIO_TRANS2(tran, _PIPEA_LINK_M2)
+#define PIPE_LINK_N2(tran) _MMIO_TRANS2(tran, _PIPEA_LINK_N2)
 
 /* CPU panel fitter */
 /* IVB+ has 3 fitters, 0 is 7x5 capable, the other two only 3x3 */
@@ -5549,11 +5605,11 @@
 #define _PFA_HSCALE		0x68090
 #define _PFB_HSCALE		0x68890
 
-#define PF_CTL(pipe)		_PIPE(pipe, _PFA_CTL_1, _PFB_CTL_1)
-#define PF_WIN_SZ(pipe)		_PIPE(pipe, _PFA_WIN_SZ, _PFB_WIN_SZ)
-#define PF_WIN_POS(pipe)	_PIPE(pipe, _PFA_WIN_POS, _PFB_WIN_POS)
-#define PF_VSCALE(pipe)		_PIPE(pipe, _PFA_VSCALE, _PFB_VSCALE)
-#define PF_HSCALE(pipe)		_PIPE(pipe, _PFA_HSCALE, _PFB_HSCALE)
+#define PF_CTL(pipe)		_MMIO_PIPE(pipe, _PFA_CTL_1, _PFB_CTL_1)
+#define PF_WIN_SZ(pipe)		_MMIO_PIPE(pipe, _PFA_WIN_SZ, _PFB_WIN_SZ)
+#define PF_WIN_POS(pipe)	_MMIO_PIPE(pipe, _PFA_WIN_POS, _PFB_WIN_POS)
+#define PF_VSCALE(pipe)		_MMIO_PIPE(pipe, _PFA_VSCALE, _PFB_VSCALE)
+#define PF_HSCALE(pipe)		_MMIO_PIPE(pipe, _PFA_HSCALE, _PFB_HSCALE)
 
 #define _PSA_CTL		0x68180
 #define _PSB_CTL		0x68980
@@ -5563,9 +5619,9 @@
 #define _PSA_WIN_POS		0x68170
 #define _PSB_WIN_POS		0x68970
 
-#define PS_CTL(pipe)		_PIPE(pipe, _PSA_CTL, _PSB_CTL)
-#define PS_WIN_SZ(pipe)		_PIPE(pipe, _PSA_WIN_SZ, _PSB_WIN_SZ)
-#define PS_WIN_POS(pipe)	_PIPE(pipe, _PSA_WIN_POS, _PSB_WIN_POS)
+#define PS_CTL(pipe)		_MMIO_PIPE(pipe, _PSA_CTL, _PSB_CTL)
+#define PS_WIN_SZ(pipe)		_MMIO_PIPE(pipe, _PSA_WIN_SZ, _PSB_WIN_SZ)
+#define PS_WIN_POS(pipe)	_MMIO_PIPE(pipe, _PSA_WIN_POS, _PSB_WIN_POS)
 
 /*
  * Skylake scalers
@@ -5654,48 +5710,63 @@
 #define _PS_ECC_STAT_1C     0x691D0
 
 #define _ID(id, a, b) ((a) + (id)*((b)-(a)))
-#define SKL_PS_CTRL(pipe, id) _PIPE(pipe,        \
+#define SKL_PS_CTRL(pipe, id) _MMIO_PIPE(pipe,        \
 			_ID(id, _PS_1A_CTRL, _PS_2A_CTRL),       \
 			_ID(id, _PS_1B_CTRL, _PS_2B_CTRL))
-#define SKL_PS_PWR_GATE(pipe, id) _PIPE(pipe,    \
+#define SKL_PS_PWR_GATE(pipe, id) _MMIO_PIPE(pipe,    \
 			_ID(id, _PS_PWR_GATE_1A, _PS_PWR_GATE_2A), \
 			_ID(id, _PS_PWR_GATE_1B, _PS_PWR_GATE_2B))
-#define SKL_PS_WIN_POS(pipe, id) _PIPE(pipe,     \
+#define SKL_PS_WIN_POS(pipe, id) _MMIO_PIPE(pipe,     \
 			_ID(id, _PS_WIN_POS_1A, _PS_WIN_POS_2A), \
 			_ID(id, _PS_WIN_POS_1B, _PS_WIN_POS_2B))
-#define SKL_PS_WIN_SZ(pipe, id)  _PIPE(pipe,     \
+#define SKL_PS_WIN_SZ(pipe, id)  _MMIO_PIPE(pipe,     \
 			_ID(id, _PS_WIN_SZ_1A, _PS_WIN_SZ_2A),   \
 			_ID(id, _PS_WIN_SZ_1B, _PS_WIN_SZ_2B))
-#define SKL_PS_VSCALE(pipe, id)  _PIPE(pipe,     \
+#define SKL_PS_VSCALE(pipe, id)  _MMIO_PIPE(pipe,     \
 			_ID(id, _PS_VSCALE_1A, _PS_VSCALE_2A),   \
 			_ID(id, _PS_VSCALE_1B, _PS_VSCALE_2B))
-#define SKL_PS_HSCALE(pipe, id)  _PIPE(pipe,     \
+#define SKL_PS_HSCALE(pipe, id)  _MMIO_PIPE(pipe,     \
 			_ID(id, _PS_HSCALE_1A, _PS_HSCALE_2A),   \
 			_ID(id, _PS_HSCALE_1B, _PS_HSCALE_2B))
-#define SKL_PS_VPHASE(pipe, id)  _PIPE(pipe,     \
+#define SKL_PS_VPHASE(pipe, id)  _MMIO_PIPE(pipe,     \
 			_ID(id, _PS_VPHASE_1A, _PS_VPHASE_2A),   \
 			_ID(id, _PS_VPHASE_1B, _PS_VPHASE_2B))
-#define SKL_PS_HPHASE(pipe, id)  _PIPE(pipe,     \
+#define SKL_PS_HPHASE(pipe, id)  _MMIO_PIPE(pipe,     \
 			_ID(id, _PS_HPHASE_1A, _PS_HPHASE_2A),   \
 			_ID(id, _PS_HPHASE_1B, _PS_HPHASE_2B))
-#define SKL_PS_ECC_STAT(pipe, id)  _PIPE(pipe,     \
+#define SKL_PS_ECC_STAT(pipe, id)  _MMIO_PIPE(pipe,     \
 			_ID(id, _PS_ECC_STAT_1A, _PS_ECC_STAT_2A),   \
-			_ID(id, _PS_ECC_STAT_1B, _PS_ECC_STAT_2B)
+			_ID(id, _PS_ECC_STAT_1B, _PS_ECC_STAT_2B))
 
 /* legacy palette */
 #define _LGC_PALETTE_A           0x4a000
 #define _LGC_PALETTE_B           0x4a800
-#define LGC_PALETTE(pipe, i) (_PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) + (i) * 4)
+#define LGC_PALETTE(pipe, i) _MMIO(_PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) + (i) * 4)
 
 #define _GAMMA_MODE_A		0x4a480
 #define _GAMMA_MODE_B		0x4ac80
-#define GAMMA_MODE(pipe) _PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B)
+#define GAMMA_MODE(pipe) _MMIO_PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B)
 #define GAMMA_MODE_MODE_MASK	(3 << 0)
 #define GAMMA_MODE_MODE_8BIT	(0 << 0)
 #define GAMMA_MODE_MODE_10BIT	(1 << 0)
 #define GAMMA_MODE_MODE_12BIT	(2 << 0)
 #define GAMMA_MODE_MODE_SPLIT	(3 << 0)
 
+/* DMC/CSR */
+#define CSR_PROGRAM(i)		_MMIO(0x80000 + (i) * 4)
+#define CSR_SSP_BASE_ADDR_GEN9	0x00002FC0
+#define CSR_HTP_ADDR_SKL	0x00500034
+#define CSR_SSP_BASE		_MMIO(0x8F074)
+#define CSR_HTP_SKL		_MMIO(0x8F004)
+#define CSR_LAST_WRITE		_MMIO(0x8F034)
+#define CSR_LAST_WRITE_VALUE	0xc003b400
+/* MMIO address range for CSR program (0x80000 - 0x82FFF) */
+#define CSR_MMIO_START_RANGE	0x80000
+#define CSR_MMIO_END_RANGE	0x8FFFF
+#define SKL_CSR_DC3_DC5_COUNT	_MMIO(0x80030)
+#define SKL_CSR_DC5_DC6_COUNT	_MMIO(0x8002C)
+#define BXT_CSR_DC3_DC5_COUNT	_MMIO(0x80038)
+
 /* interrupts */
 #define DE_MASTER_IRQ_CONTROL   (1 << 31)
 #define DE_SPRITEB_FLIP_DONE    (1 << 29)
@@ -5747,20 +5818,20 @@
 #define DE_PIPEA_VBLANK_IVB		(1<<0)
 #define DE_PIPE_VBLANK_IVB(pipe)	(1 << ((pipe) * 5))
 
-#define VLV_MASTER_IER			0x4400c /* Gunit master IER */
+#define VLV_MASTER_IER			_MMIO(0x4400c) /* Gunit master IER */
 #define   MASTER_INTERRUPT_ENABLE	(1<<31)
 
-#define DEISR   0x44000
-#define DEIMR   0x44004
-#define DEIIR   0x44008
-#define DEIER   0x4400c
+#define DEISR   _MMIO(0x44000)
+#define DEIMR   _MMIO(0x44004)
+#define DEIIR   _MMIO(0x44008)
+#define DEIER   _MMIO(0x4400c)
 
-#define GTISR   0x44010
-#define GTIMR   0x44014
-#define GTIIR   0x44018
-#define GTIER   0x4401c
+#define GTISR   _MMIO(0x44010)
+#define GTIMR   _MMIO(0x44014)
+#define GTIIR   _MMIO(0x44018)
+#define GTIER   _MMIO(0x4401c)
 
-#define GEN8_MASTER_IRQ			0x44200
+#define GEN8_MASTER_IRQ			_MMIO(0x44200)
 #define  GEN8_MASTER_IRQ_CONTROL	(1<<31)
 #define  GEN8_PCU_IRQ			(1<<30)
 #define  GEN8_DE_PCH_IRQ		(1<<23)
@@ -5777,10 +5848,10 @@
 #define  GEN8_GT_BCS_IRQ		(1<<1)
 #define  GEN8_GT_RCS_IRQ		(1<<0)
 
-#define GEN8_GT_ISR(which) (0x44300 + (0x10 * (which)))
-#define GEN8_GT_IMR(which) (0x44304 + (0x10 * (which)))
-#define GEN8_GT_IIR(which) (0x44308 + (0x10 * (which)))
-#define GEN8_GT_IER(which) (0x4430c + (0x10 * (which)))
+#define GEN8_GT_ISR(which) _MMIO(0x44300 + (0x10 * (which)))
+#define GEN8_GT_IMR(which) _MMIO(0x44304 + (0x10 * (which)))
+#define GEN8_GT_IIR(which) _MMIO(0x44308 + (0x10 * (which)))
+#define GEN8_GT_IER(which) _MMIO(0x4430c + (0x10 * (which)))
 
 #define GEN8_RCS_IRQ_SHIFT 0
 #define GEN8_BCS_IRQ_SHIFT 16
@@ -5789,10 +5860,10 @@
 #define GEN8_VECS_IRQ_SHIFT 0
 #define GEN8_WD_IRQ_SHIFT 16
 
-#define GEN8_DE_PIPE_ISR(pipe) (0x44400 + (0x10 * (pipe)))
-#define GEN8_DE_PIPE_IMR(pipe) (0x44404 + (0x10 * (pipe)))
-#define GEN8_DE_PIPE_IIR(pipe) (0x44408 + (0x10 * (pipe)))
-#define GEN8_DE_PIPE_IER(pipe) (0x4440c + (0x10 * (pipe)))
+#define GEN8_DE_PIPE_ISR(pipe) _MMIO(0x44400 + (0x10 * (pipe)))
+#define GEN8_DE_PIPE_IMR(pipe) _MMIO(0x44404 + (0x10 * (pipe)))
+#define GEN8_DE_PIPE_IIR(pipe) _MMIO(0x44408 + (0x10 * (pipe)))
+#define GEN8_DE_PIPE_IER(pipe) _MMIO(0x4440c + (0x10 * (pipe)))
 #define  GEN8_PIPE_FIFO_UNDERRUN	(1 << 31)
 #define  GEN8_PIPE_CDCLK_CRC_ERROR	(1 << 29)
 #define  GEN8_PIPE_CDCLK_CRC_DONE	(1 << 28)
@@ -5825,10 +5896,10 @@
 	 GEN9_PIPE_PLANE2_FAULT | \
 	 GEN9_PIPE_PLANE1_FAULT)
 
-#define GEN8_DE_PORT_ISR 0x44440
-#define GEN8_DE_PORT_IMR 0x44444
-#define GEN8_DE_PORT_IIR 0x44448
-#define GEN8_DE_PORT_IER 0x4444c
+#define GEN8_DE_PORT_ISR _MMIO(0x44440)
+#define GEN8_DE_PORT_IMR _MMIO(0x44444)
+#define GEN8_DE_PORT_IIR _MMIO(0x44448)
+#define GEN8_DE_PORT_IER _MMIO(0x4444c)
 #define  GEN9_AUX_CHANNEL_D		(1 << 27)
 #define  GEN9_AUX_CHANNEL_C		(1 << 26)
 #define  GEN9_AUX_CHANNEL_B		(1 << 25)
@@ -5842,23 +5913,23 @@
 #define  BXT_DE_PORT_GMBUS		(1 << 1)
 #define  GEN8_AUX_CHANNEL_A		(1 << 0)
 
-#define GEN8_DE_MISC_ISR 0x44460
-#define GEN8_DE_MISC_IMR 0x44464
-#define GEN8_DE_MISC_IIR 0x44468
-#define GEN8_DE_MISC_IER 0x4446c
+#define GEN8_DE_MISC_ISR _MMIO(0x44460)
+#define GEN8_DE_MISC_IMR _MMIO(0x44464)
+#define GEN8_DE_MISC_IIR _MMIO(0x44468)
+#define GEN8_DE_MISC_IER _MMIO(0x4446c)
 #define  GEN8_DE_MISC_GSE		(1 << 27)
 
-#define GEN8_PCU_ISR 0x444e0
-#define GEN8_PCU_IMR 0x444e4
-#define GEN8_PCU_IIR 0x444e8
-#define GEN8_PCU_IER 0x444ec
+#define GEN8_PCU_ISR _MMIO(0x444e0)
+#define GEN8_PCU_IMR _MMIO(0x444e4)
+#define GEN8_PCU_IIR _MMIO(0x444e8)
+#define GEN8_PCU_IER _MMIO(0x444ec)
 
-#define ILK_DISPLAY_CHICKEN2	0x42004
+#define ILK_DISPLAY_CHICKEN2	_MMIO(0x42004)
 /* Required on all Ironlake and Sandybridge according to the B-Spec. */
 #define  ILK_ELPIN_409_SELECT	(1 << 25)
 #define  ILK_DPARB_GATE	(1<<22)
 #define  ILK_VSDPFD_FULL	(1<<21)
-#define FUSE_STRAP			0x42014
+#define FUSE_STRAP			_MMIO(0x42014)
 #define  ILK_INTERNAL_GRAPHICS_DISABLE	(1 << 31)
 #define  ILK_INTERNAL_DISPLAY_DISABLE	(1 << 30)
 #define  ILK_DISPLAY_DEBUG_DISABLE	(1 << 29)
@@ -5867,18 +5938,18 @@
 #define  HSW_CDCLK_LIMIT		(1 << 24)
 #define  ILK_DESKTOP			(1 << 23)
 
-#define ILK_DSPCLK_GATE_D			0x42020
+#define ILK_DSPCLK_GATE_D			_MMIO(0x42020)
 #define   ILK_VRHUNIT_CLOCK_GATE_DISABLE	(1 << 28)
 #define   ILK_DPFCUNIT_CLOCK_GATE_DISABLE	(1 << 9)
 #define   ILK_DPFCRUNIT_CLOCK_GATE_DISABLE	(1 << 8)
 #define   ILK_DPFDUNIT_CLOCK_GATE_ENABLE	(1 << 7)
 #define   ILK_DPARBUNIT_CLOCK_GATE_ENABLE	(1 << 5)
 
-#define IVB_CHICKEN3	0x4200c
+#define IVB_CHICKEN3	_MMIO(0x4200c)
 # define CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE	(1 << 5)
 # define CHICKEN3_DGMG_DONE_FIX_DISABLE		(1 << 2)
 
-#define CHICKEN_PAR1_1		0x42080
+#define CHICKEN_PAR1_1		_MMIO(0x42080)
 #define  DPA_MASK_VBLANK_SRD	(1 << 15)
 #define  FORCE_ARB_IDLE_PLANES	(1 << 14)
 
@@ -5886,70 +5957,70 @@
 #define _CHICKEN_PIPESL_1_B	0x420b4
 #define  HSW_FBCQ_DIS			(1 << 22)
 #define  BDW_DPRS_MASK_VBLANK_SRD	(1 << 0)
-#define CHICKEN_PIPESL_1(pipe) _PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B)
+#define CHICKEN_PIPESL_1(pipe) _MMIO_PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B)
 
-#define DISP_ARB_CTL	0x45000
+#define DISP_ARB_CTL	_MMIO(0x45000)
 #define  DISP_TILE_SURFACE_SWIZZLING	(1<<13)
 #define  DISP_FBC_WM_DIS		(1<<15)
-#define DISP_ARB_CTL2	0x45004
+#define DISP_ARB_CTL2	_MMIO(0x45004)
 #define  DISP_DATA_PARTITION_5_6	(1<<6)
-#define DBUF_CTL	0x45008
+#define DBUF_CTL	_MMIO(0x45008)
 #define  DBUF_POWER_REQUEST		(1<<31)
 #define  DBUF_POWER_STATE		(1<<30)
-#define GEN7_MSG_CTL	0x45010
+#define GEN7_MSG_CTL	_MMIO(0x45010)
 #define  WAIT_FOR_PCH_RESET_ACK		(1<<1)
 #define  WAIT_FOR_PCH_FLR_ACK		(1<<0)
-#define HSW_NDE_RSTWRN_OPT	0x46408
+#define HSW_NDE_RSTWRN_OPT	_MMIO(0x46408)
 #define  RESET_PCH_HANDSHAKE_ENABLE	(1<<4)
 
-#define SKL_DFSM			0x51000
+#define SKL_DFSM			_MMIO(0x51000)
 #define SKL_DFSM_CDCLK_LIMIT_MASK	(3 << 23)
 #define SKL_DFSM_CDCLK_LIMIT_675	(0 << 23)
 #define SKL_DFSM_CDCLK_LIMIT_540	(1 << 23)
 #define SKL_DFSM_CDCLK_LIMIT_450	(2 << 23)
 #define SKL_DFSM_CDCLK_LIMIT_337_5	(3 << 23)
 
-#define FF_SLICE_CS_CHICKEN2			0x20e4
+#define FF_SLICE_CS_CHICKEN2			_MMIO(0x20e4)
 #define  GEN9_TSG_BARRIER_ACK_DISABLE		(1<<8)
 
 /* GEN7 chicken */
-#define GEN7_COMMON_SLICE_CHICKEN1		0x7010
+#define GEN7_COMMON_SLICE_CHICKEN1		_MMIO(0x7010)
 # define GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC	((1<<10) | (1<<26))
 # define GEN9_RHWO_OPTIMIZATION_DISABLE		(1<<14)
-#define COMMON_SLICE_CHICKEN2			0x7014
+#define COMMON_SLICE_CHICKEN2			_MMIO(0x7014)
 # define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE	(1<<0)
 
-#define HIZ_CHICKEN					0x7018
+#define HIZ_CHICKEN					_MMIO(0x7018)
 # define CHV_HZ_8X8_MODE_IN_1X				(1<<15)
 # define BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE	(1<<3)
 
-#define GEN9_SLICE_COMMON_ECO_CHICKEN0		0x7308
+#define GEN9_SLICE_COMMON_ECO_CHICKEN0		_MMIO(0x7308)
 #define  DISABLE_PIXEL_MASK_CAMMING		(1<<14)
 
-#define GEN7_L3SQCREG1				0xB010
+#define GEN7_L3SQCREG1				_MMIO(0xB010)
 #define  VLV_B0_WA_L3SQCREG1_VALUE		0x00D30000
 
-#define GEN8_L3SQCREG1				0xB100
+#define GEN8_L3SQCREG1				_MMIO(0xB100)
 #define  BDW_WA_L3SQCREG1_DEFAULT		0x784000
 
-#define GEN7_L3CNTLREG1				0xB01C
+#define GEN7_L3CNTLREG1				_MMIO(0xB01C)
 #define  GEN7_WA_FOR_GEN7_L3_CONTROL			0x3C47FF8C
 #define  GEN7_L3AGDIS				(1<<19)
-#define GEN7_L3CNTLREG2				0xB020
-#define GEN7_L3CNTLREG3				0xB024
+#define GEN7_L3CNTLREG2				_MMIO(0xB020)
+#define GEN7_L3CNTLREG3				_MMIO(0xB024)
 
-#define GEN7_L3_CHICKEN_MODE_REGISTER		0xB030
+#define GEN7_L3_CHICKEN_MODE_REGISTER		_MMIO(0xB030)
 #define  GEN7_WA_L3_CHICKEN_MODE				0x20000000
 
-#define GEN7_L3SQCREG4				0xb034
+#define GEN7_L3SQCREG4				_MMIO(0xb034)
 #define  L3SQ_URB_READ_CAM_MATCH_DISABLE	(1<<27)
 
-#define GEN8_L3SQCREG4				0xb118
+#define GEN8_L3SQCREG4				_MMIO(0xb118)
 #define  GEN8_LQSC_RO_PERF_DIS			(1<<27)
 #define  GEN8_LQSC_FLUSH_COHERENT_LINES		(1<<21)
 
 /* GEN8 chicken */
-#define HDC_CHICKEN0				0x7300
+#define HDC_CHICKEN0				_MMIO(0x7300)
 #define  HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE	(1<<15)
 #define  HDC_FENCE_DEST_SLM_DISABLE		(1<<14)
 #define  HDC_DONOT_FETCH_MEM_WHEN_MASKED	(1<<11)
@@ -5958,17 +6029,17 @@
 #define  HDC_BARRIER_PERFORMANCE_DISABLE	(1<<10)
 
 /* GEN9 chicken */
-#define SLICE_ECO_CHICKEN0			0x7308
+#define SLICE_ECO_CHICKEN0			_MMIO(0x7308)
 #define   PIXEL_MASK_CAMMING_DISABLE		(1 << 14)
 
 /* WaCatErrorRejectionIssue */
-#define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG		0x9030
+#define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG		_MMIO(0x9030)
 #define  GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB	(1<<11)
 
-#define HSW_SCRATCH1				0xb038
+#define HSW_SCRATCH1				_MMIO(0xb038)
 #define  HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE	(1<<27)
 
-#define BDW_SCRATCH1					0xb11c
+#define BDW_SCRATCH1					_MMIO(0xb11c)
 #define  GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE	(1<<2)
 
 /* PCH */
@@ -6062,12 +6133,12 @@
 				 SDE_FDI_RXB_CPT | \
 				 SDE_FDI_RXA_CPT)
 
-#define SDEISR  0xc4000
-#define SDEIMR  0xc4004
-#define SDEIIR  0xc4008
-#define SDEIER  0xc400c
+#define SDEISR  _MMIO(0xc4000)
+#define SDEIMR  _MMIO(0xc4004)
+#define SDEIIR  _MMIO(0xc4008)
+#define SDEIER  _MMIO(0xc400c)
 
-#define SERR_INT			0xc4040
+#define SERR_INT			_MMIO(0xc4040)
 #define  SERR_INT_POISON		(1<<31)
 #define  SERR_INT_TRANS_C_FIFO_UNDERRUN	(1<<6)
 #define  SERR_INT_TRANS_B_FIFO_UNDERRUN	(1<<3)
@@ -6075,7 +6146,7 @@
 #define  SERR_INT_TRANS_FIFO_UNDERRUN(pipe)	(1<<((pipe)*3))
 
 /* digital port hotplug */
-#define PCH_PORT_HOTPLUG		0xc4030	/* SHOTPLUG_CTL */
+#define PCH_PORT_HOTPLUG		_MMIO(0xc4030)	/* SHOTPLUG_CTL */
 #define  PORTA_HOTPLUG_ENABLE		(1 << 28) /* LPT:LP+ & BXT */
 #define  PORTA_HOTPLUG_STATUS_MASK	(3 << 24) /* SPT+ & BXT */
 #define  PORTA_HOTPLUG_NO_DETECT	(0 << 24) /* SPT+ & BXT */
@@ -6112,42 +6183,42 @@
 #define  PORTB_HOTPLUG_SHORT_DETECT	(1 << 0)
 #define  PORTB_HOTPLUG_LONG_DETECT	(2 << 0)
 
-#define PCH_PORT_HOTPLUG2		0xc403C	/* SHOTPLUG_CTL2 SPT+ */
+#define PCH_PORT_HOTPLUG2		_MMIO(0xc403C)	/* SHOTPLUG_CTL2 SPT+ */
 #define  PORTE_HOTPLUG_ENABLE		(1 << 4)
 #define  PORTE_HOTPLUG_STATUS_MASK	(3 << 0)
 #define  PORTE_HOTPLUG_NO_DETECT	(0 << 0)
 #define  PORTE_HOTPLUG_SHORT_DETECT	(1 << 0)
 #define  PORTE_HOTPLUG_LONG_DETECT	(2 << 0)
 
-#define PCH_GPIOA               0xc5010
-#define PCH_GPIOB               0xc5014
-#define PCH_GPIOC               0xc5018
-#define PCH_GPIOD               0xc501c
-#define PCH_GPIOE               0xc5020
-#define PCH_GPIOF               0xc5024
+#define PCH_GPIOA               _MMIO(0xc5010)
+#define PCH_GPIOB               _MMIO(0xc5014)
+#define PCH_GPIOC               _MMIO(0xc5018)
+#define PCH_GPIOD               _MMIO(0xc501c)
+#define PCH_GPIOE               _MMIO(0xc5020)
+#define PCH_GPIOF               _MMIO(0xc5024)
 
-#define PCH_GMBUS0		0xc5100
-#define PCH_GMBUS1		0xc5104
-#define PCH_GMBUS2		0xc5108
-#define PCH_GMBUS3		0xc510c
-#define PCH_GMBUS4		0xc5110
-#define PCH_GMBUS5		0xc5120
+#define PCH_GMBUS0		_MMIO(0xc5100)
+#define PCH_GMBUS1		_MMIO(0xc5104)
+#define PCH_GMBUS2		_MMIO(0xc5108)
+#define PCH_GMBUS3		_MMIO(0xc510c)
+#define PCH_GMBUS4		_MMIO(0xc5110)
+#define PCH_GMBUS5		_MMIO(0xc5120)
 
 #define _PCH_DPLL_A              0xc6014
 #define _PCH_DPLL_B              0xc6018
-#define PCH_DPLL(pll) (pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B)
+#define PCH_DPLL(pll) _MMIO(pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B)
 
 #define _PCH_FPA0                0xc6040
 #define  FP_CB_TUNE		(0x3<<22)
 #define _PCH_FPA1                0xc6044
 #define _PCH_FPB0                0xc6048
 #define _PCH_FPB1                0xc604c
-#define PCH_FP0(pll) (pll == 0 ? _PCH_FPA0 : _PCH_FPB0)
-#define PCH_FP1(pll) (pll == 0 ? _PCH_FPA1 : _PCH_FPB1)
+#define PCH_FP0(pll) _MMIO(pll == 0 ? _PCH_FPA0 : _PCH_FPB0)
+#define PCH_FP1(pll) _MMIO(pll == 0 ? _PCH_FPA1 : _PCH_FPB1)
 
-#define PCH_DPLL_TEST           0xc606c
+#define PCH_DPLL_TEST           _MMIO(0xc606c)
 
-#define PCH_DREF_CONTROL        0xC6200
+#define PCH_DREF_CONTROL        _MMIO(0xC6200)
 #define  DREF_CONTROL_MASK      0x7fc3
 #define  DREF_CPU_SOURCE_OUTPUT_DISABLE         (0<<13)
 #define  DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD      (2<<13)
@@ -6170,19 +6241,19 @@
 #define  DREF_SSC4_DISABLE                      (0)
 #define  DREF_SSC4_ENABLE                       (1)
 
-#define PCH_RAWCLK_FREQ         0xc6204
+#define PCH_RAWCLK_FREQ         _MMIO(0xc6204)
 #define  FDL_TP1_TIMER_SHIFT    12
 #define  FDL_TP1_TIMER_MASK     (3<<12)
 #define  FDL_TP2_TIMER_SHIFT    10
 #define  FDL_TP2_TIMER_MASK     (3<<10)
 #define  RAWCLK_FREQ_MASK       0x3ff
 
-#define PCH_DPLL_TMR_CFG        0xc6208
+#define PCH_DPLL_TMR_CFG        _MMIO(0xc6208)
 
-#define PCH_SSC4_PARMS          0xc6210
-#define PCH_SSC4_AUX_PARMS      0xc6214
+#define PCH_SSC4_PARMS          _MMIO(0xc6210)
+#define PCH_SSC4_AUX_PARMS      _MMIO(0xc6214)
 
-#define PCH_DPLL_SEL		0xc7000
+#define PCH_DPLL_SEL		_MMIO(0xc7000)
 #define	 TRANS_DPLLB_SEL(pipe)		(1 << ((pipe) * 4))
 #define	 TRANS_DPLLA_SEL(pipe)		0
 #define  TRANS_DPLL_ENABLE(pipe)	(1 << ((pipe) * 4 + 3))
@@ -6230,79 +6301,73 @@
 #define _VIDEO_DIP_DATA_B        0xe1208
 #define _VIDEO_DIP_GCP_B         0xe1210
 
-#define TVIDEO_DIP_CTL(pipe) _PIPE(pipe, _VIDEO_DIP_CTL_A, _VIDEO_DIP_CTL_B)
-#define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B)
-#define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B)
+#define TVIDEO_DIP_CTL(pipe) _MMIO_PIPE(pipe, _VIDEO_DIP_CTL_A, _VIDEO_DIP_CTL_B)
+#define TVIDEO_DIP_DATA(pipe) _MMIO_PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B)
+#define TVIDEO_DIP_GCP(pipe) _MMIO_PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B)
 
 /* Per-transcoder DIP controls (VLV) */
-#define VLV_VIDEO_DIP_CTL_A		(VLV_DISPLAY_BASE + 0x60200)
-#define VLV_VIDEO_DIP_DATA_A		(VLV_DISPLAY_BASE + 0x60208)
-#define VLV_VIDEO_DIP_GDCP_PAYLOAD_A	(VLV_DISPLAY_BASE + 0x60210)
+#define _VLV_VIDEO_DIP_CTL_A		(VLV_DISPLAY_BASE + 0x60200)
+#define _VLV_VIDEO_DIP_DATA_A		(VLV_DISPLAY_BASE + 0x60208)
+#define _VLV_VIDEO_DIP_GDCP_PAYLOAD_A	(VLV_DISPLAY_BASE + 0x60210)
 
-#define VLV_VIDEO_DIP_CTL_B		(VLV_DISPLAY_BASE + 0x61170)
-#define VLV_VIDEO_DIP_DATA_B		(VLV_DISPLAY_BASE + 0x61174)
-#define VLV_VIDEO_DIP_GDCP_PAYLOAD_B	(VLV_DISPLAY_BASE + 0x61178)
+#define _VLV_VIDEO_DIP_CTL_B		(VLV_DISPLAY_BASE + 0x61170)
+#define _VLV_VIDEO_DIP_DATA_B		(VLV_DISPLAY_BASE + 0x61174)
+#define _VLV_VIDEO_DIP_GDCP_PAYLOAD_B	(VLV_DISPLAY_BASE + 0x61178)
 
-#define CHV_VIDEO_DIP_CTL_C		(VLV_DISPLAY_BASE + 0x611f0)
-#define CHV_VIDEO_DIP_DATA_C		(VLV_DISPLAY_BASE + 0x611f4)
-#define CHV_VIDEO_DIP_GDCP_PAYLOAD_C	(VLV_DISPLAY_BASE + 0x611f8)
+#define _CHV_VIDEO_DIP_CTL_C		(VLV_DISPLAY_BASE + 0x611f0)
+#define _CHV_VIDEO_DIP_DATA_C		(VLV_DISPLAY_BASE + 0x611f4)
+#define _CHV_VIDEO_DIP_GDCP_PAYLOAD_C	(VLV_DISPLAY_BASE + 0x611f8)
 
 #define VLV_TVIDEO_DIP_CTL(pipe) \
-	_PIPE3((pipe), VLV_VIDEO_DIP_CTL_A, \
-	       VLV_VIDEO_DIP_CTL_B, CHV_VIDEO_DIP_CTL_C)
+	_MMIO_PIPE3((pipe), _VLV_VIDEO_DIP_CTL_A, \
+	       _VLV_VIDEO_DIP_CTL_B, _CHV_VIDEO_DIP_CTL_C)
 #define VLV_TVIDEO_DIP_DATA(pipe) \
-	_PIPE3((pipe), VLV_VIDEO_DIP_DATA_A, \
-	       VLV_VIDEO_DIP_DATA_B, CHV_VIDEO_DIP_DATA_C)
+	_MMIO_PIPE3((pipe), _VLV_VIDEO_DIP_DATA_A, \
+	       _VLV_VIDEO_DIP_DATA_B, _CHV_VIDEO_DIP_DATA_C)
 #define VLV_TVIDEO_DIP_GCP(pipe) \
-	_PIPE3((pipe), VLV_VIDEO_DIP_GDCP_PAYLOAD_A, \
-		VLV_VIDEO_DIP_GDCP_PAYLOAD_B, CHV_VIDEO_DIP_GDCP_PAYLOAD_C)
+	_MMIO_PIPE3((pipe), _VLV_VIDEO_DIP_GDCP_PAYLOAD_A, \
+		_VLV_VIDEO_DIP_GDCP_PAYLOAD_B, _CHV_VIDEO_DIP_GDCP_PAYLOAD_C)
 
 /* Haswell DIP controls */
-#define HSW_VIDEO_DIP_CTL_A		0x60200
-#define HSW_VIDEO_DIP_AVI_DATA_A	0x60220
-#define HSW_VIDEO_DIP_VS_DATA_A		0x60260
-#define HSW_VIDEO_DIP_SPD_DATA_A	0x602A0
-#define HSW_VIDEO_DIP_GMP_DATA_A	0x602E0
-#define HSW_VIDEO_DIP_VSC_DATA_A	0x60320
-#define HSW_VIDEO_DIP_AVI_ECC_A		0x60240
-#define HSW_VIDEO_DIP_VS_ECC_A		0x60280
-#define HSW_VIDEO_DIP_SPD_ECC_A		0x602C0
-#define HSW_VIDEO_DIP_GMP_ECC_A		0x60300
-#define HSW_VIDEO_DIP_VSC_ECC_A		0x60344
-#define HSW_VIDEO_DIP_GCP_A		0x60210
 
-#define HSW_VIDEO_DIP_CTL_B		0x61200
-#define HSW_VIDEO_DIP_AVI_DATA_B	0x61220
-#define HSW_VIDEO_DIP_VS_DATA_B		0x61260
-#define HSW_VIDEO_DIP_SPD_DATA_B	0x612A0
-#define HSW_VIDEO_DIP_GMP_DATA_B	0x612E0
-#define HSW_VIDEO_DIP_VSC_DATA_B	0x61320
-#define HSW_VIDEO_DIP_BVI_ECC_B		0x61240
-#define HSW_VIDEO_DIP_VS_ECC_B		0x61280
-#define HSW_VIDEO_DIP_SPD_ECC_B		0x612C0
-#define HSW_VIDEO_DIP_GMP_ECC_B		0x61300
-#define HSW_VIDEO_DIP_VSC_ECC_B		0x61344
-#define HSW_VIDEO_DIP_GCP_B		0x61210
+#define _HSW_VIDEO_DIP_CTL_A		0x60200
+#define _HSW_VIDEO_DIP_AVI_DATA_A	0x60220
+#define _HSW_VIDEO_DIP_VS_DATA_A	0x60260
+#define _HSW_VIDEO_DIP_SPD_DATA_A	0x602A0
+#define _HSW_VIDEO_DIP_GMP_DATA_A	0x602E0
+#define _HSW_VIDEO_DIP_VSC_DATA_A	0x60320
+#define _HSW_VIDEO_DIP_AVI_ECC_A	0x60240
+#define _HSW_VIDEO_DIP_VS_ECC_A		0x60280
+#define _HSW_VIDEO_DIP_SPD_ECC_A	0x602C0
+#define _HSW_VIDEO_DIP_GMP_ECC_A	0x60300
+#define _HSW_VIDEO_DIP_VSC_ECC_A	0x60344
+#define _HSW_VIDEO_DIP_GCP_A		0x60210
 
-#define HSW_TVIDEO_DIP_CTL(trans) \
-	 _TRANSCODER2(trans, HSW_VIDEO_DIP_CTL_A)
-#define HSW_TVIDEO_DIP_AVI_DATA(trans, i) \
-	(_TRANSCODER2(trans, HSW_VIDEO_DIP_AVI_DATA_A) + (i) * 4)
-#define HSW_TVIDEO_DIP_VS_DATA(trans, i) \
-	(_TRANSCODER2(trans, HSW_VIDEO_DIP_VS_DATA_A) + (i) * 4)
-#define HSW_TVIDEO_DIP_SPD_DATA(trans, i) \
-	(_TRANSCODER2(trans, HSW_VIDEO_DIP_SPD_DATA_A) + (i) * 4)
-#define HSW_TVIDEO_DIP_GCP(trans) \
-	_TRANSCODER2(trans, HSW_VIDEO_DIP_GCP_A)
-#define HSW_TVIDEO_DIP_VSC_DATA(trans, i) \
-	(_TRANSCODER2(trans, HSW_VIDEO_DIP_VSC_DATA_A) + (i) * 4)
+#define _HSW_VIDEO_DIP_CTL_B		0x61200
+#define _HSW_VIDEO_DIP_AVI_DATA_B	0x61220
+#define _HSW_VIDEO_DIP_VS_DATA_B	0x61260
+#define _HSW_VIDEO_DIP_SPD_DATA_B	0x612A0
+#define _HSW_VIDEO_DIP_GMP_DATA_B	0x612E0
+#define _HSW_VIDEO_DIP_VSC_DATA_B	0x61320
+#define _HSW_VIDEO_DIP_BVI_ECC_B	0x61240
+#define _HSW_VIDEO_DIP_VS_ECC_B		0x61280
+#define _HSW_VIDEO_DIP_SPD_ECC_B	0x612C0
+#define _HSW_VIDEO_DIP_GMP_ECC_B	0x61300
+#define _HSW_VIDEO_DIP_VSC_ECC_B	0x61344
+#define _HSW_VIDEO_DIP_GCP_B		0x61210
 
-#define HSW_STEREO_3D_CTL_A	0x70020
-#define   S3D_ENABLE		(1<<31)
-#define HSW_STEREO_3D_CTL_B	0x71020
+#define HSW_TVIDEO_DIP_CTL(trans)		_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_CTL_A)
+#define HSW_TVIDEO_DIP_AVI_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_AVI_DATA_A + (i) * 4)
+#define HSW_TVIDEO_DIP_VS_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_VS_DATA_A + (i) * 4)
+#define HSW_TVIDEO_DIP_SPD_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_SPD_DATA_A + (i) * 4)
+#define HSW_TVIDEO_DIP_GCP(trans)		_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_GCP_A)
+#define HSW_TVIDEO_DIP_VSC_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_VSC_DATA_A + (i) * 4)
 
-#define HSW_STEREO_3D_CTL(trans) \
-	_PIPE2(trans, HSW_STEREO_3D_CTL_A)
+#define _HSW_STEREO_3D_CTL_A		0x70020
+#define   S3D_ENABLE			(1<<31)
+#define _HSW_STEREO_3D_CTL_B		0x71020
+
+#define HSW_STEREO_3D_CTL(trans)	_MMIO_PIPE2(trans, _HSW_STEREO_3D_CTL_A)
 
 #define _PCH_TRANS_HTOTAL_B          0xe1000
 #define _PCH_TRANS_HBLANK_B          0xe1004
@@ -6310,16 +6375,15 @@
 #define _PCH_TRANS_VTOTAL_B          0xe100c
 #define _PCH_TRANS_VBLANK_B          0xe1010
 #define _PCH_TRANS_VSYNC_B           0xe1014
-#define _PCH_TRANS_VSYNCSHIFT_B	 0xe1028
+#define _PCH_TRANS_VSYNCSHIFT_B 0xe1028
 
-#define PCH_TRANS_HTOTAL(pipe) _PIPE(pipe, _PCH_TRANS_HTOTAL_A, _PCH_TRANS_HTOTAL_B)
-#define PCH_TRANS_HBLANK(pipe) _PIPE(pipe, _PCH_TRANS_HBLANK_A, _PCH_TRANS_HBLANK_B)
-#define PCH_TRANS_HSYNC(pipe) _PIPE(pipe, _PCH_TRANS_HSYNC_A, _PCH_TRANS_HSYNC_B)
-#define PCH_TRANS_VTOTAL(pipe) _PIPE(pipe, _PCH_TRANS_VTOTAL_A, _PCH_TRANS_VTOTAL_B)
-#define PCH_TRANS_VBLANK(pipe) _PIPE(pipe, _PCH_TRANS_VBLANK_A, _PCH_TRANS_VBLANK_B)
-#define PCH_TRANS_VSYNC(pipe) _PIPE(pipe, _PCH_TRANS_VSYNC_A, _PCH_TRANS_VSYNC_B)
-#define PCH_TRANS_VSYNCSHIFT(pipe) _PIPE(pipe, _PCH_TRANS_VSYNCSHIFT_A, \
-					 _PCH_TRANS_VSYNCSHIFT_B)
+#define PCH_TRANS_HTOTAL(pipe)		_MMIO_PIPE(pipe, _PCH_TRANS_HTOTAL_A, _PCH_TRANS_HTOTAL_B)
+#define PCH_TRANS_HBLANK(pipe)		_MMIO_PIPE(pipe, _PCH_TRANS_HBLANK_A, _PCH_TRANS_HBLANK_B)
+#define PCH_TRANS_HSYNC(pipe)		_MMIO_PIPE(pipe, _PCH_TRANS_HSYNC_A, _PCH_TRANS_HSYNC_B)
+#define PCH_TRANS_VTOTAL(pipe)		_MMIO_PIPE(pipe, _PCH_TRANS_VTOTAL_A, _PCH_TRANS_VTOTAL_B)
+#define PCH_TRANS_VBLANK(pipe)		_MMIO_PIPE(pipe, _PCH_TRANS_VBLANK_A, _PCH_TRANS_VBLANK_B)
+#define PCH_TRANS_VSYNC(pipe)		_MMIO_PIPE(pipe, _PCH_TRANS_VSYNC_A, _PCH_TRANS_VSYNC_B)
+#define PCH_TRANS_VSYNCSHIFT(pipe)	_MMIO_PIPE(pipe, _PCH_TRANS_VSYNCSHIFT_A, _PCH_TRANS_VSYNCSHIFT_B)
 
 #define _PCH_TRANSB_DATA_M1	0xe1030
 #define _PCH_TRANSB_DATA_N1	0xe1034
@@ -6330,19 +6394,19 @@
 #define _PCH_TRANSB_LINK_M2	0xe1048
 #define _PCH_TRANSB_LINK_N2	0xe104c
 
-#define PCH_TRANS_DATA_M1(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_M1, _PCH_TRANSB_DATA_M1)
-#define PCH_TRANS_DATA_N1(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_N1, _PCH_TRANSB_DATA_N1)
-#define PCH_TRANS_DATA_M2(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_M2, _PCH_TRANSB_DATA_M2)
-#define PCH_TRANS_DATA_N2(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_N2, _PCH_TRANSB_DATA_N2)
-#define PCH_TRANS_LINK_M1(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_M1, _PCH_TRANSB_LINK_M1)
-#define PCH_TRANS_LINK_N1(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_N1, _PCH_TRANSB_LINK_N1)
-#define PCH_TRANS_LINK_M2(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_M2, _PCH_TRANSB_LINK_M2)
-#define PCH_TRANS_LINK_N2(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_N2, _PCH_TRANSB_LINK_N2)
+#define PCH_TRANS_DATA_M1(pipe)	_MMIO_PIPE(pipe, _PCH_TRANSA_DATA_M1, _PCH_TRANSB_DATA_M1)
+#define PCH_TRANS_DATA_N1(pipe)	_MMIO_PIPE(pipe, _PCH_TRANSA_DATA_N1, _PCH_TRANSB_DATA_N1)
+#define PCH_TRANS_DATA_M2(pipe)	_MMIO_PIPE(pipe, _PCH_TRANSA_DATA_M2, _PCH_TRANSB_DATA_M2)
+#define PCH_TRANS_DATA_N2(pipe)	_MMIO_PIPE(pipe, _PCH_TRANSA_DATA_N2, _PCH_TRANSB_DATA_N2)
+#define PCH_TRANS_LINK_M1(pipe)	_MMIO_PIPE(pipe, _PCH_TRANSA_LINK_M1, _PCH_TRANSB_LINK_M1)
+#define PCH_TRANS_LINK_N1(pipe)	_MMIO_PIPE(pipe, _PCH_TRANSA_LINK_N1, _PCH_TRANSB_LINK_N1)
+#define PCH_TRANS_LINK_M2(pipe)	_MMIO_PIPE(pipe, _PCH_TRANSA_LINK_M2, _PCH_TRANSB_LINK_M2)
+#define PCH_TRANS_LINK_N2(pipe)	_MMIO_PIPE(pipe, _PCH_TRANSA_LINK_N2, _PCH_TRANSB_LINK_N2)
 
 #define _PCH_TRANSACONF              0xf0008
 #define _PCH_TRANSBCONF              0xf1008
-#define PCH_TRANSCONF(pipe) _PIPE(pipe, _PCH_TRANSACONF, _PCH_TRANSBCONF)
-#define LPT_TRANSCONF		_PCH_TRANSACONF /* lpt has only one transcoder */
+#define PCH_TRANSCONF(pipe)	_MMIO_PIPE(pipe, _PCH_TRANSACONF, _PCH_TRANSBCONF)
+#define LPT_TRANSCONF		PCH_TRANSCONF(PIPE_A) /* lpt has only one transcoder */
 #define  TRANS_DISABLE          (0<<31)
 #define  TRANS_ENABLE           (1<<31)
 #define  TRANS_STATE_MASK       (1<<30)
@@ -6363,47 +6427,47 @@
 
 #define _TRANSA_CHICKEN1	 0xf0060
 #define _TRANSB_CHICKEN1	 0xf1060
-#define TRANS_CHICKEN1(pipe) _PIPE(pipe, _TRANSA_CHICKEN1, _TRANSB_CHICKEN1)
+#define TRANS_CHICKEN1(pipe)	_MMIO_PIPE(pipe, _TRANSA_CHICKEN1, _TRANSB_CHICKEN1)
 #define  TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE	(1<<10)
 #define  TRANS_CHICKEN1_DP0UNIT_GC_DISABLE	(1<<4)
 #define _TRANSA_CHICKEN2	 0xf0064
 #define _TRANSB_CHICKEN2	 0xf1064
-#define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2)
+#define TRANS_CHICKEN2(pipe)	_MMIO_PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2)
 #define  TRANS_CHICKEN2_TIMING_OVERRIDE			(1<<31)
 #define  TRANS_CHICKEN2_FDI_POLARITY_REVERSED		(1<<29)
 #define  TRANS_CHICKEN2_FRAME_START_DELAY_MASK		(3<<27)
 #define  TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER	(1<<26)
 #define  TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH	(1<<25)
 
-#define SOUTH_CHICKEN1		0xc2000
+#define SOUTH_CHICKEN1		_MMIO(0xc2000)
 #define  FDIA_PHASE_SYNC_SHIFT_OVR	19
 #define  FDIA_PHASE_SYNC_SHIFT_EN	18
 #define  FDI_PHASE_SYNC_OVR(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2)))
 #define  FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2)))
 #define  FDI_BC_BIFURCATION_SELECT	(1 << 12)
 #define  SPT_PWM_GRANULARITY		(1<<0)
-#define SOUTH_CHICKEN2		0xc2004
+#define SOUTH_CHICKEN2		_MMIO(0xc2004)
 #define  FDI_MPHY_IOSFSB_RESET_STATUS	(1<<13)
 #define  FDI_MPHY_IOSFSB_RESET_CTL	(1<<12)
 #define  LPT_PWM_GRANULARITY		(1<<5)
 #define  DPLS_EDP_PPS_FIX_DIS		(1<<0)
 
-#define _FDI_RXA_CHICKEN         0xc200c
-#define _FDI_RXB_CHICKEN         0xc2010
+#define _FDI_RXA_CHICKEN        0xc200c
+#define _FDI_RXB_CHICKEN        0xc2010
 #define  FDI_RX_PHASE_SYNC_POINTER_OVR	(1<<1)
 #define  FDI_RX_PHASE_SYNC_POINTER_EN	(1<<0)
-#define FDI_RX_CHICKEN(pipe) _PIPE(pipe, _FDI_RXA_CHICKEN, _FDI_RXB_CHICKEN)
+#define FDI_RX_CHICKEN(pipe)	_MMIO_PIPE(pipe, _FDI_RXA_CHICKEN, _FDI_RXB_CHICKEN)
 
-#define SOUTH_DSPCLK_GATE_D	0xc2020
+#define SOUTH_DSPCLK_GATE_D	_MMIO(0xc2020)
 #define  PCH_DPLUNIT_CLOCK_GATE_DISABLE (1<<30)
 #define  PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29)
 #define  PCH_CPUNIT_CLOCK_GATE_DISABLE (1<<14)
 #define  PCH_LP_PARTITION_LEVEL_DISABLE  (1<<12)
 
 /* CPU: FDI_TX */
-#define _FDI_TXA_CTL             0x60100
-#define _FDI_TXB_CTL             0x61100
-#define FDI_TX_CTL(pipe) _PIPE(pipe, _FDI_TXA_CTL, _FDI_TXB_CTL)
+#define _FDI_TXA_CTL            0x60100
+#define _FDI_TXB_CTL            0x61100
+#define FDI_TX_CTL(pipe)	_MMIO_PIPE(pipe, _FDI_TXA_CTL, _FDI_TXB_CTL)
 #define  FDI_TX_DISABLE         (0<<31)
 #define  FDI_TX_ENABLE          (1<<31)
 #define  FDI_LINK_TRAIN_PATTERN_1       (0<<28)
@@ -6453,7 +6517,7 @@
 /* FDI_RX, FDI_X is hard-wired to Transcoder_X */
 #define _FDI_RXA_CTL             0xf000c
 #define _FDI_RXB_CTL             0xf100c
-#define FDI_RX_CTL(pipe) _PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL)
+#define FDI_RX_CTL(pipe)	_MMIO_PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL)
 #define  FDI_RX_ENABLE          (1<<31)
 /* train, dp width same as FDI_TX */
 #define  FDI_FS_ERRC_ENABLE		(1<<27)
@@ -6489,14 +6553,14 @@
 #define  FDI_RX_TP1_TO_TP2_48		(2<<20)
 #define  FDI_RX_TP1_TO_TP2_64		(3<<20)
 #define  FDI_RX_FDI_DELAY_90		(0x90<<0)
-#define FDI_RX_MISC(pipe) _PIPE(pipe, _FDI_RXA_MISC, _FDI_RXB_MISC)
+#define FDI_RX_MISC(pipe)	_MMIO_PIPE(pipe, _FDI_RXA_MISC, _FDI_RXB_MISC)
 
-#define _FDI_RXA_TUSIZE1         0xf0030
-#define _FDI_RXA_TUSIZE2         0xf0038
-#define _FDI_RXB_TUSIZE1         0xf1030
-#define _FDI_RXB_TUSIZE2         0xf1038
-#define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE1, _FDI_RXB_TUSIZE1)
-#define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE2, _FDI_RXB_TUSIZE2)
+#define _FDI_RXA_TUSIZE1        0xf0030
+#define _FDI_RXA_TUSIZE2        0xf0038
+#define _FDI_RXB_TUSIZE1        0xf1030
+#define _FDI_RXB_TUSIZE2        0xf1038
+#define FDI_RX_TUSIZE1(pipe)	_MMIO_PIPE(pipe, _FDI_RXA_TUSIZE1, _FDI_RXB_TUSIZE1)
+#define FDI_RX_TUSIZE2(pipe)	_MMIO_PIPE(pipe, _FDI_RXA_TUSIZE2, _FDI_RXB_TUSIZE2)
 
 /* FDI_RX interrupt register format */
 #define FDI_RX_INTER_LANE_ALIGN         (1<<10)
@@ -6511,44 +6575,41 @@
 #define FDI_RX_CROSS_CLOCK_OVERFLOW     (1<<1)
 #define FDI_RX_SYMBOL_QUEUE_OVERFLOW    (1<<0)
 
-#define _FDI_RXA_IIR             0xf0014
-#define _FDI_RXA_IMR             0xf0018
-#define _FDI_RXB_IIR             0xf1014
-#define _FDI_RXB_IMR             0xf1018
-#define FDI_RX_IIR(pipe) _PIPE(pipe, _FDI_RXA_IIR, _FDI_RXB_IIR)
-#define FDI_RX_IMR(pipe) _PIPE(pipe, _FDI_RXA_IMR, _FDI_RXB_IMR)
+#define _FDI_RXA_IIR            0xf0014
+#define _FDI_RXA_IMR            0xf0018
+#define _FDI_RXB_IIR            0xf1014
+#define _FDI_RXB_IMR            0xf1018
+#define FDI_RX_IIR(pipe)	_MMIO_PIPE(pipe, _FDI_RXA_IIR, _FDI_RXB_IIR)
+#define FDI_RX_IMR(pipe)	_MMIO_PIPE(pipe, _FDI_RXA_IMR, _FDI_RXB_IMR)
 
-#define FDI_PLL_CTL_1           0xfe000
-#define FDI_PLL_CTL_2           0xfe004
+#define FDI_PLL_CTL_1           _MMIO(0xfe000)
+#define FDI_PLL_CTL_2           _MMIO(0xfe004)
 
-#define PCH_LVDS	0xe1180
+#define PCH_LVDS	_MMIO(0xe1180)
 #define  LVDS_DETECTED	(1 << 1)
 
 /* vlv has 2 sets of panel control regs. */
-#define PIPEA_PP_STATUS         (VLV_DISPLAY_BASE + 0x61200)
-#define PIPEA_PP_CONTROL        (VLV_DISPLAY_BASE + 0x61204)
-#define PIPEA_PP_ON_DELAYS      (VLV_DISPLAY_BASE + 0x61208)
+#define _PIPEA_PP_STATUS         (VLV_DISPLAY_BASE + 0x61200)
+#define _PIPEA_PP_CONTROL        (VLV_DISPLAY_BASE + 0x61204)
+#define _PIPEA_PP_ON_DELAYS      (VLV_DISPLAY_BASE + 0x61208)
 #define  PANEL_PORT_SELECT_VLV(port)	((port) << 30)
-#define PIPEA_PP_OFF_DELAYS     (VLV_DISPLAY_BASE + 0x6120c)
-#define PIPEA_PP_DIVISOR        (VLV_DISPLAY_BASE + 0x61210)
+#define _PIPEA_PP_OFF_DELAYS     (VLV_DISPLAY_BASE + 0x6120c)
+#define _PIPEA_PP_DIVISOR        (VLV_DISPLAY_BASE + 0x61210)
 
-#define PIPEB_PP_STATUS         (VLV_DISPLAY_BASE + 0x61300)
-#define PIPEB_PP_CONTROL        (VLV_DISPLAY_BASE + 0x61304)
-#define PIPEB_PP_ON_DELAYS      (VLV_DISPLAY_BASE + 0x61308)
-#define PIPEB_PP_OFF_DELAYS     (VLV_DISPLAY_BASE + 0x6130c)
-#define PIPEB_PP_DIVISOR        (VLV_DISPLAY_BASE + 0x61310)
+#define _PIPEB_PP_STATUS         (VLV_DISPLAY_BASE + 0x61300)
+#define _PIPEB_PP_CONTROL        (VLV_DISPLAY_BASE + 0x61304)
+#define _PIPEB_PP_ON_DELAYS      (VLV_DISPLAY_BASE + 0x61308)
+#define _PIPEB_PP_OFF_DELAYS     (VLV_DISPLAY_BASE + 0x6130c)
+#define _PIPEB_PP_DIVISOR        (VLV_DISPLAY_BASE + 0x61310)
 
-#define VLV_PIPE_PP_STATUS(pipe) _PIPE(pipe, PIPEA_PP_STATUS, PIPEB_PP_STATUS)
-#define VLV_PIPE_PP_CONTROL(pipe) _PIPE(pipe, PIPEA_PP_CONTROL, PIPEB_PP_CONTROL)
-#define VLV_PIPE_PP_ON_DELAYS(pipe) \
-		_PIPE(pipe, PIPEA_PP_ON_DELAYS, PIPEB_PP_ON_DELAYS)
-#define VLV_PIPE_PP_OFF_DELAYS(pipe) \
-		_PIPE(pipe, PIPEA_PP_OFF_DELAYS, PIPEB_PP_OFF_DELAYS)
-#define VLV_PIPE_PP_DIVISOR(pipe) \
-		_PIPE(pipe, PIPEA_PP_DIVISOR, PIPEB_PP_DIVISOR)
+#define VLV_PIPE_PP_STATUS(pipe)	_MMIO_PIPE(pipe, _PIPEA_PP_STATUS, _PIPEB_PP_STATUS)
+#define VLV_PIPE_PP_CONTROL(pipe)	_MMIO_PIPE(pipe, _PIPEA_PP_CONTROL, _PIPEB_PP_CONTROL)
+#define VLV_PIPE_PP_ON_DELAYS(pipe)	_MMIO_PIPE(pipe, _PIPEA_PP_ON_DELAYS, _PIPEB_PP_ON_DELAYS)
+#define VLV_PIPE_PP_OFF_DELAYS(pipe)	_MMIO_PIPE(pipe, _PIPEA_PP_OFF_DELAYS, _PIPEB_PP_OFF_DELAYS)
+#define VLV_PIPE_PP_DIVISOR(pipe)	_MMIO_PIPE(pipe, _PIPEA_PP_DIVISOR, _PIPEB_PP_DIVISOR)
 
-#define PCH_PP_STATUS		0xc7200
-#define PCH_PP_CONTROL		0xc7204
+#define _PCH_PP_STATUS		0xc7200
+#define _PCH_PP_CONTROL		0xc7204
 #define  PANEL_UNLOCK_REGS	(0xabcd << 16)
 #define  PANEL_UNLOCK_MASK	(0xffff << 16)
 #define  BXT_POWER_CYCLE_DELAY_MASK	(0x1f0)
@@ -6558,7 +6619,7 @@
 #define  PANEL_POWER_RESET	(1 << 1)
 #define  PANEL_POWER_OFF	(0 << 0)
 #define  PANEL_POWER_ON		(1 << 0)
-#define PCH_PP_ON_DELAYS	0xc7208
+#define _PCH_PP_ON_DELAYS	0xc7208
 #define  PANEL_PORT_SELECT_MASK	(3 << 30)
 #define  PANEL_PORT_SELECT_LVDS	(0 << 30)
 #define  PANEL_PORT_SELECT_DPA	(1 << 30)
@@ -6569,52 +6630,64 @@
 #define  PANEL_LIGHT_ON_DELAY_MASK	(0x1fff)
 #define  PANEL_LIGHT_ON_DELAY_SHIFT	0
 
-#define PCH_PP_OFF_DELAYS	0xc720c
+#define _PCH_PP_OFF_DELAYS		0xc720c
 #define  PANEL_POWER_DOWN_DELAY_MASK	(0x1fff0000)
 #define  PANEL_POWER_DOWN_DELAY_SHIFT	16
 #define  PANEL_LIGHT_OFF_DELAY_MASK	(0x1fff)
 #define  PANEL_LIGHT_OFF_DELAY_SHIFT	0
 
-#define PCH_PP_DIVISOR		0xc7210
+#define _PCH_PP_DIVISOR			0xc7210
 #define  PP_REFERENCE_DIVIDER_MASK	(0xffffff00)
 #define  PP_REFERENCE_DIVIDER_SHIFT	8
 #define  PANEL_POWER_CYCLE_DELAY_MASK	(0x1f)
 #define  PANEL_POWER_CYCLE_DELAY_SHIFT	0
 
+#define PCH_PP_STATUS			_MMIO(_PCH_PP_STATUS)
+#define PCH_PP_CONTROL			_MMIO(_PCH_PP_CONTROL)
+#define PCH_PP_ON_DELAYS		_MMIO(_PCH_PP_ON_DELAYS)
+#define PCH_PP_OFF_DELAYS		_MMIO(_PCH_PP_OFF_DELAYS)
+#define PCH_PP_DIVISOR			_MMIO(_PCH_PP_DIVISOR)
+
 /* BXT PPS changes - 2nd set of PPS registers */
 #define _BXT_PP_STATUS2 	0xc7300
 #define _BXT_PP_CONTROL2 	0xc7304
 #define _BXT_PP_ON_DELAYS2	0xc7308
 #define _BXT_PP_OFF_DELAYS2	0xc730c
 
-#define BXT_PP_STATUS(n)	_PIPE(n, PCH_PP_STATUS, _BXT_PP_STATUS2)
-#define BXT_PP_CONTROL(n)	_PIPE(n, PCH_PP_CONTROL, _BXT_PP_CONTROL2)
-#define BXT_PP_ON_DELAYS(n)	_PIPE(n, PCH_PP_ON_DELAYS, _BXT_PP_ON_DELAYS2)
-#define BXT_PP_OFF_DELAYS(n)	_PIPE(n, PCH_PP_OFF_DELAYS, _BXT_PP_OFF_DELAYS2)
+#define BXT_PP_STATUS(n)	_MMIO_PIPE(n, _PCH_PP_STATUS, _BXT_PP_STATUS2)
+#define BXT_PP_CONTROL(n)	_MMIO_PIPE(n, _PCH_PP_CONTROL, _BXT_PP_CONTROL2)
+#define BXT_PP_ON_DELAYS(n)	_MMIO_PIPE(n, _PCH_PP_ON_DELAYS, _BXT_PP_ON_DELAYS2)
+#define BXT_PP_OFF_DELAYS(n)	_MMIO_PIPE(n, _PCH_PP_OFF_DELAYS, _BXT_PP_OFF_DELAYS2)
 
-#define PCH_DP_B		0xe4100
-#define PCH_DPB_AUX_CH_CTL	0xe4110
-#define PCH_DPB_AUX_CH_DATA1	0xe4114
-#define PCH_DPB_AUX_CH_DATA2	0xe4118
-#define PCH_DPB_AUX_CH_DATA3	0xe411c
-#define PCH_DPB_AUX_CH_DATA4	0xe4120
-#define PCH_DPB_AUX_CH_DATA5	0xe4124
+#define _PCH_DP_B		0xe4100
+#define PCH_DP_B		_MMIO(_PCH_DP_B)
+#define _PCH_DPB_AUX_CH_CTL	0xe4110
+#define _PCH_DPB_AUX_CH_DATA1	0xe4114
+#define _PCH_DPB_AUX_CH_DATA2	0xe4118
+#define _PCH_DPB_AUX_CH_DATA3	0xe411c
+#define _PCH_DPB_AUX_CH_DATA4	0xe4120
+#define _PCH_DPB_AUX_CH_DATA5	0xe4124
 
-#define PCH_DP_C		0xe4200
-#define PCH_DPC_AUX_CH_CTL	0xe4210
-#define PCH_DPC_AUX_CH_DATA1	0xe4214
-#define PCH_DPC_AUX_CH_DATA2	0xe4218
-#define PCH_DPC_AUX_CH_DATA3	0xe421c
-#define PCH_DPC_AUX_CH_DATA4	0xe4220
-#define PCH_DPC_AUX_CH_DATA5	0xe4224
+#define _PCH_DP_C		0xe4200
+#define PCH_DP_C		_MMIO(_PCH_DP_C)
+#define _PCH_DPC_AUX_CH_CTL	0xe4210
+#define _PCH_DPC_AUX_CH_DATA1	0xe4214
+#define _PCH_DPC_AUX_CH_DATA2	0xe4218
+#define _PCH_DPC_AUX_CH_DATA3	0xe421c
+#define _PCH_DPC_AUX_CH_DATA4	0xe4220
+#define _PCH_DPC_AUX_CH_DATA5	0xe4224
 
-#define PCH_DP_D		0xe4300
-#define PCH_DPD_AUX_CH_CTL	0xe4310
-#define PCH_DPD_AUX_CH_DATA1	0xe4314
-#define PCH_DPD_AUX_CH_DATA2	0xe4318
-#define PCH_DPD_AUX_CH_DATA3	0xe431c
-#define PCH_DPD_AUX_CH_DATA4	0xe4320
-#define PCH_DPD_AUX_CH_DATA5	0xe4324
+#define _PCH_DP_D		0xe4300
+#define PCH_DP_D		_MMIO(_PCH_DP_D)
+#define _PCH_DPD_AUX_CH_CTL	0xe4310
+#define _PCH_DPD_AUX_CH_DATA1	0xe4314
+#define _PCH_DPD_AUX_CH_DATA2	0xe4318
+#define _PCH_DPD_AUX_CH_DATA3	0xe431c
+#define _PCH_DPD_AUX_CH_DATA4	0xe4320
+#define _PCH_DPD_AUX_CH_DATA5	0xe4324
+
+#define PCH_DP_AUX_CH_CTL(port)		_MMIO_PORT((port) - PORT_B, _PCH_DPB_AUX_CH_CTL, _PCH_DPC_AUX_CH_CTL)
+#define PCH_DP_AUX_CH_DATA(port, i)	_MMIO(_PORT((port) - PORT_B, _PCH_DPB_AUX_CH_DATA1, _PCH_DPC_AUX_CH_DATA1) + (i) * 4) /* 5 registers */
 
 /* CPT */
 #define  PORT_TRANS_A_SEL_CPT	0
@@ -6627,10 +6700,10 @@
 #define  SDVO_PORT_TO_PIPE_CHV(val)	(((val) & (3<<24)) >> 24)
 #define  DP_PORT_TO_PIPE_CHV(val)	(((val) & (3<<16)) >> 16)
 
-#define TRANS_DP_CTL_A		0xe0300
-#define TRANS_DP_CTL_B		0xe1300
-#define TRANS_DP_CTL_C		0xe2300
-#define TRANS_DP_CTL(pipe)	_PIPE(pipe, TRANS_DP_CTL_A, TRANS_DP_CTL_B)
+#define _TRANS_DP_CTL_A		0xe0300
+#define _TRANS_DP_CTL_B		0xe1300
+#define _TRANS_DP_CTL_C		0xe2300
+#define TRANS_DP_CTL(pipe)	_MMIO_PIPE(pipe, _TRANS_DP_CTL_A, _TRANS_DP_CTL_B)
 #define  TRANS_DP_OUTPUT_ENABLE	(1<<31)
 #define  TRANS_DP_PORT_SEL_B	(0<<29)
 #define  TRANS_DP_PORT_SEL_C	(1<<29)
@@ -6683,40 +6756,40 @@
 
 #define  EDP_LINK_TRAIN_VOL_EMP_MASK_IVB	(0x3f<<22)
 
-#define  VLV_PMWGICZ				0x1300a4
+#define  VLV_PMWGICZ				_MMIO(0x1300a4)
 
-#define  FORCEWAKE				0xA18C
-#define  FORCEWAKE_VLV				0x1300b0
-#define  FORCEWAKE_ACK_VLV			0x1300b4
-#define  FORCEWAKE_MEDIA_VLV			0x1300b8
-#define  FORCEWAKE_ACK_MEDIA_VLV		0x1300bc
-#define  FORCEWAKE_ACK_HSW			0x130044
-#define  FORCEWAKE_ACK				0x130090
-#define  VLV_GTLC_WAKE_CTRL			0x130090
+#define  FORCEWAKE				_MMIO(0xA18C)
+#define  FORCEWAKE_VLV				_MMIO(0x1300b0)
+#define  FORCEWAKE_ACK_VLV			_MMIO(0x1300b4)
+#define  FORCEWAKE_MEDIA_VLV			_MMIO(0x1300b8)
+#define  FORCEWAKE_ACK_MEDIA_VLV		_MMIO(0x1300bc)
+#define  FORCEWAKE_ACK_HSW			_MMIO(0x130044)
+#define  FORCEWAKE_ACK				_MMIO(0x130090)
+#define  VLV_GTLC_WAKE_CTRL			_MMIO(0x130090)
 #define   VLV_GTLC_RENDER_CTX_EXISTS		(1 << 25)
 #define   VLV_GTLC_MEDIA_CTX_EXISTS		(1 << 24)
 #define   VLV_GTLC_ALLOWWAKEREQ			(1 << 0)
 
-#define  VLV_GTLC_PW_STATUS			0x130094
+#define  VLV_GTLC_PW_STATUS			_MMIO(0x130094)
 #define   VLV_GTLC_ALLOWWAKEACK			(1 << 0)
 #define   VLV_GTLC_ALLOWWAKEERR			(1 << 1)
 #define   VLV_GTLC_PW_MEDIA_STATUS_MASK		(1 << 5)
 #define   VLV_GTLC_PW_RENDER_STATUS_MASK	(1 << 7)
-#define  FORCEWAKE_MT				0xa188 /* multi-threaded */
-#define  FORCEWAKE_MEDIA_GEN9			0xa270
-#define  FORCEWAKE_RENDER_GEN9			0xa278
-#define  FORCEWAKE_BLITTER_GEN9			0xa188
-#define  FORCEWAKE_ACK_MEDIA_GEN9		0x0D88
-#define  FORCEWAKE_ACK_RENDER_GEN9		0x0D84
-#define  FORCEWAKE_ACK_BLITTER_GEN9		0x130044
+#define  FORCEWAKE_MT				_MMIO(0xa188) /* multi-threaded */
+#define  FORCEWAKE_MEDIA_GEN9			_MMIO(0xa270)
+#define  FORCEWAKE_RENDER_GEN9			_MMIO(0xa278)
+#define  FORCEWAKE_BLITTER_GEN9			_MMIO(0xa188)
+#define  FORCEWAKE_ACK_MEDIA_GEN9		_MMIO(0x0D88)
+#define  FORCEWAKE_ACK_RENDER_GEN9		_MMIO(0x0D84)
+#define  FORCEWAKE_ACK_BLITTER_GEN9		_MMIO(0x130044)
 #define   FORCEWAKE_KERNEL			0x1
 #define   FORCEWAKE_USER			0x2
-#define  FORCEWAKE_MT_ACK			0x130040
-#define  ECOBUS					0xa180
+#define  FORCEWAKE_MT_ACK			_MMIO(0x130040)
+#define  ECOBUS					_MMIO(0xa180)
 #define    FORCEWAKE_MT_ENABLE			(1<<5)
-#define  VLV_SPAREG2H				0xA194
+#define  VLV_SPAREG2H				_MMIO(0xA194)
 
-#define  GTFIFODBG				0x120000
+#define  GTFIFODBG				_MMIO(0x120000)
 #define    GT_FIFO_SBDROPERR			(1<<6)
 #define    GT_FIFO_BLOBDROPERR			(1<<5)
 #define    GT_FIFO_SB_READ_ABORTERR		(1<<4)
@@ -6725,23 +6798,23 @@
 #define    GT_FIFO_IAWRERR			(1<<1)
 #define    GT_FIFO_IARDERR			(1<<0)
 
-#define  GTFIFOCTL				0x120008
+#define  GTFIFOCTL				_MMIO(0x120008)
 #define    GT_FIFO_FREE_ENTRIES_MASK		0x7f
 #define    GT_FIFO_NUM_RESERVED_ENTRIES		20
 #define    GT_FIFO_CTL_BLOCK_ALL_POLICY_STALL	(1 << 12)
 #define    GT_FIFO_CTL_RC6_POLICY_STALL		(1 << 11)
 
-#define  HSW_IDICR				0x9008
+#define  HSW_IDICR				_MMIO(0x9008)
 #define    IDIHASHMSK(x)			(((x) & 0x3f) << 16)
-#define  HSW_EDRAM_PRESENT			0x120010
+#define  HSW_EDRAM_PRESENT			_MMIO(0x120010)
 #define    EDRAM_ENABLED			0x1
 
-#define GEN6_UCGCTL1				0x9400
+#define GEN6_UCGCTL1				_MMIO(0x9400)
 # define GEN6_EU_TCUNIT_CLOCK_GATE_DISABLE		(1 << 16)
 # define GEN6_BLBUNIT_CLOCK_GATE_DISABLE		(1 << 5)
 # define GEN6_CSUNIT_CLOCK_GATE_DISABLE			(1 << 7)
 
-#define GEN6_UCGCTL2				0x9404
+#define GEN6_UCGCTL2				_MMIO(0x9404)
 # define GEN6_VFUNIT_CLOCK_GATE_DISABLE			(1 << 31)
 # define GEN7_VDSUNIT_CLOCK_GATE_DISABLE		(1 << 30)
 # define GEN7_TDLUNIT_CLOCK_GATE_DISABLE		(1 << 22)
@@ -6749,30 +6822,30 @@
 # define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE		(1 << 12)
 # define GEN6_RCCUNIT_CLOCK_GATE_DISABLE		(1 << 11)
 
-#define GEN6_UCGCTL3				0x9408
+#define GEN6_UCGCTL3				_MMIO(0x9408)
 
-#define GEN7_UCGCTL4				0x940c
+#define GEN7_UCGCTL4				_MMIO(0x940c)
 #define  GEN7_L3BANK2X_CLOCK_GATE_DISABLE	(1<<25)
 
-#define GEN6_RCGCTL1				0x9410
-#define GEN6_RCGCTL2				0x9414
-#define GEN6_RSTCTL				0x9420
+#define GEN6_RCGCTL1				_MMIO(0x9410)
+#define GEN6_RCGCTL2				_MMIO(0x9414)
+#define GEN6_RSTCTL				_MMIO(0x9420)
 
-#define GEN8_UCGCTL6				0x9430
+#define GEN8_UCGCTL6				_MMIO(0x9430)
 #define   GEN8_GAPSUNIT_CLOCK_GATE_DISABLE	(1<<24)
 #define   GEN8_SDEUNIT_CLOCK_GATE_DISABLE	(1<<14)
 #define   GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ (1<<28)
 
-#define GEN6_GFXPAUSE				0xA000
-#define GEN6_RPNSWREQ				0xA008
+#define GEN6_GFXPAUSE				_MMIO(0xA000)
+#define GEN6_RPNSWREQ				_MMIO(0xA008)
 #define   GEN6_TURBO_DISABLE			(1<<31)
 #define   GEN6_FREQUENCY(x)			((x)<<25)
 #define   HSW_FREQUENCY(x)			((x)<<24)
 #define   GEN9_FREQUENCY(x)			((x)<<23)
 #define   GEN6_OFFSET(x)			((x)<<19)
 #define   GEN6_AGGRESSIVE_TURBO			(0<<15)
-#define GEN6_RC_VIDEO_FREQ			0xA00C
-#define GEN6_RC_CONTROL				0xA090
+#define GEN6_RC_VIDEO_FREQ			_MMIO(0xA00C)
+#define GEN6_RC_CONTROL				_MMIO(0xA090)
 #define   GEN6_RC_CTL_RC6pp_ENABLE		(1<<16)
 #define   GEN6_RC_CTL_RC6p_ENABLE		(1<<17)
 #define   GEN6_RC_CTL_RC6_ENABLE		(1<<18)
@@ -6782,16 +6855,16 @@
 #define   GEN7_RC_CTL_TO_MODE			(1<<28)
 #define   GEN6_RC_CTL_EI_MODE(x)		((x)<<27)
 #define   GEN6_RC_CTL_HW_ENABLE			(1<<31)
-#define GEN6_RP_DOWN_TIMEOUT			0xA010
-#define GEN6_RP_INTERRUPT_LIMITS		0xA014
-#define GEN6_RPSTAT1				0xA01C
+#define GEN6_RP_DOWN_TIMEOUT			_MMIO(0xA010)
+#define GEN6_RP_INTERRUPT_LIMITS		_MMIO(0xA014)
+#define GEN6_RPSTAT1				_MMIO(0xA01C)
 #define   GEN6_CAGF_SHIFT			8
 #define   HSW_CAGF_SHIFT			7
 #define   GEN9_CAGF_SHIFT			23
 #define   GEN6_CAGF_MASK			(0x7f << GEN6_CAGF_SHIFT)
 #define   HSW_CAGF_MASK				(0x7f << HSW_CAGF_SHIFT)
 #define   GEN9_CAGF_MASK			(0x1ff << GEN9_CAGF_SHIFT)
-#define GEN6_RP_CONTROL				0xA024
+#define GEN6_RP_CONTROL				_MMIO(0xA024)
 #define   GEN6_RP_MEDIA_TURBO			(1<<11)
 #define   GEN6_RP_MEDIA_MODE_MASK		(3<<9)
 #define   GEN6_RP_MEDIA_HW_TURBO_MODE		(3<<9)
@@ -6805,53 +6878,53 @@
 #define   GEN6_RP_UP_BUSY_CONT			(0x4<<3)
 #define   GEN6_RP_DOWN_IDLE_AVG			(0x2<<0)
 #define   GEN6_RP_DOWN_IDLE_CONT		(0x1<<0)
-#define GEN6_RP_UP_THRESHOLD			0xA02C
-#define GEN6_RP_DOWN_THRESHOLD			0xA030
-#define GEN6_RP_CUR_UP_EI			0xA050
+#define GEN6_RP_UP_THRESHOLD			_MMIO(0xA02C)
+#define GEN6_RP_DOWN_THRESHOLD			_MMIO(0xA030)
+#define GEN6_RP_CUR_UP_EI			_MMIO(0xA050)
 #define   GEN6_CURICONT_MASK			0xffffff
-#define GEN6_RP_CUR_UP				0xA054
+#define GEN6_RP_CUR_UP				_MMIO(0xA054)
 #define   GEN6_CURBSYTAVG_MASK			0xffffff
-#define GEN6_RP_PREV_UP				0xA058
-#define GEN6_RP_CUR_DOWN_EI			0xA05C
+#define GEN6_RP_PREV_UP				_MMIO(0xA058)
+#define GEN6_RP_CUR_DOWN_EI			_MMIO(0xA05C)
 #define   GEN6_CURIAVG_MASK			0xffffff
-#define GEN6_RP_CUR_DOWN			0xA060
-#define GEN6_RP_PREV_DOWN			0xA064
-#define GEN6_RP_UP_EI				0xA068
-#define GEN6_RP_DOWN_EI				0xA06C
-#define GEN6_RP_IDLE_HYSTERSIS			0xA070
-#define GEN6_RPDEUHWTC				0xA080
-#define GEN6_RPDEUC				0xA084
-#define GEN6_RPDEUCSW				0xA088
-#define GEN6_RC_STATE				0xA094
-#define GEN6_RC1_WAKE_RATE_LIMIT		0xA098
-#define GEN6_RC6_WAKE_RATE_LIMIT		0xA09C
-#define GEN6_RC6pp_WAKE_RATE_LIMIT		0xA0A0
-#define GEN6_RC_EVALUATION_INTERVAL		0xA0A8
-#define GEN6_RC_IDLE_HYSTERSIS			0xA0AC
-#define GEN6_RC_SLEEP				0xA0B0
-#define GEN6_RCUBMABDTMR			0xA0B0
-#define GEN6_RC1e_THRESHOLD			0xA0B4
-#define GEN6_RC6_THRESHOLD			0xA0B8
-#define GEN6_RC6p_THRESHOLD			0xA0BC
-#define VLV_RCEDATA				0xA0BC
-#define GEN6_RC6pp_THRESHOLD			0xA0C0
-#define GEN6_PMINTRMSK				0xA168
+#define GEN6_RP_CUR_DOWN			_MMIO(0xA060)
+#define GEN6_RP_PREV_DOWN			_MMIO(0xA064)
+#define GEN6_RP_UP_EI				_MMIO(0xA068)
+#define GEN6_RP_DOWN_EI				_MMIO(0xA06C)
+#define GEN6_RP_IDLE_HYSTERSIS			_MMIO(0xA070)
+#define GEN6_RPDEUHWTC				_MMIO(0xA080)
+#define GEN6_RPDEUC				_MMIO(0xA084)
+#define GEN6_RPDEUCSW				_MMIO(0xA088)
+#define GEN6_RC_STATE				_MMIO(0xA094)
+#define GEN6_RC1_WAKE_RATE_LIMIT		_MMIO(0xA098)
+#define GEN6_RC6_WAKE_RATE_LIMIT		_MMIO(0xA09C)
+#define GEN6_RC6pp_WAKE_RATE_LIMIT		_MMIO(0xA0A0)
+#define GEN6_RC_EVALUATION_INTERVAL		_MMIO(0xA0A8)
+#define GEN6_RC_IDLE_HYSTERSIS			_MMIO(0xA0AC)
+#define GEN6_RC_SLEEP				_MMIO(0xA0B0)
+#define GEN6_RCUBMABDTMR			_MMIO(0xA0B0)
+#define GEN6_RC1e_THRESHOLD			_MMIO(0xA0B4)
+#define GEN6_RC6_THRESHOLD			_MMIO(0xA0B8)
+#define GEN6_RC6p_THRESHOLD			_MMIO(0xA0BC)
+#define VLV_RCEDATA				_MMIO(0xA0BC)
+#define GEN6_RC6pp_THRESHOLD			_MMIO(0xA0C0)
+#define GEN6_PMINTRMSK				_MMIO(0xA168)
 #define GEN8_PMINTR_REDIRECT_TO_NON_DISP	(1<<31)
-#define VLV_PWRDWNUPCTL				0xA294
-#define GEN9_MEDIA_PG_IDLE_HYSTERESIS		0xA0C4
-#define GEN9_RENDER_PG_IDLE_HYSTERESIS		0xA0C8
-#define GEN9_PG_ENABLE				0xA210
+#define VLV_PWRDWNUPCTL				_MMIO(0xA294)
+#define GEN9_MEDIA_PG_IDLE_HYSTERESIS		_MMIO(0xA0C4)
+#define GEN9_RENDER_PG_IDLE_HYSTERESIS		_MMIO(0xA0C8)
+#define GEN9_PG_ENABLE				_MMIO(0xA210)
 #define GEN9_RENDER_PG_ENABLE			(1<<0)
 #define GEN9_MEDIA_PG_ENABLE			(1<<1)
 
-#define VLV_CHICKEN_3				(VLV_DISPLAY_BASE + 0x7040C)
+#define VLV_CHICKEN_3				_MMIO(VLV_DISPLAY_BASE + 0x7040C)
 #define  PIXEL_OVERLAP_CNT_MASK			(3 << 30)
 #define  PIXEL_OVERLAP_CNT_SHIFT		30
 
-#define GEN6_PMISR				0x44020
-#define GEN6_PMIMR				0x44024 /* rps_lock */
-#define GEN6_PMIIR				0x44028
-#define GEN6_PMIER				0x4402C
+#define GEN6_PMISR				_MMIO(0x44020)
+#define GEN6_PMIMR				_MMIO(0x44024) /* rps_lock */
+#define GEN6_PMIIR				_MMIO(0x44028)
+#define GEN6_PMIER				_MMIO(0x4402C)
 #define  GEN6_PM_MBOX_EVENT			(1<<25)
 #define  GEN6_PM_THERMAL_EVENT			(1<<24)
 #define  GEN6_PM_RP_DOWN_TIMEOUT		(1<<6)
@@ -6863,30 +6936,30 @@
 						 GEN6_PM_RP_DOWN_THRESHOLD | \
 						 GEN6_PM_RP_DOWN_TIMEOUT)
 
-#define GEN7_GT_SCRATCH(i)			(0x4F100 + (i) * 4)
+#define GEN7_GT_SCRATCH(i)			_MMIO(0x4F100 + (i) * 4)
 #define GEN7_GT_SCRATCH_REG_NUM			8
 
-#define VLV_GTLC_SURVIVABILITY_REG              0x130098
+#define VLV_GTLC_SURVIVABILITY_REG              _MMIO(0x130098)
 #define VLV_GFX_CLK_STATUS_BIT			(1<<3)
 #define VLV_GFX_CLK_FORCE_ON_BIT		(1<<2)
 
-#define GEN6_GT_GFX_RC6_LOCKED			0x138104
-#define VLV_COUNTER_CONTROL			0x138104
+#define GEN6_GT_GFX_RC6_LOCKED			_MMIO(0x138104)
+#define VLV_COUNTER_CONTROL			_MMIO(0x138104)
 #define   VLV_COUNT_RANGE_HIGH			(1<<15)
 #define   VLV_MEDIA_RC0_COUNT_EN		(1<<5)
 #define   VLV_RENDER_RC0_COUNT_EN		(1<<4)
 #define   VLV_MEDIA_RC6_COUNT_EN		(1<<1)
 #define   VLV_RENDER_RC6_COUNT_EN		(1<<0)
-#define GEN6_GT_GFX_RC6				0x138108
-#define VLV_GT_RENDER_RC6			0x138108
-#define VLV_GT_MEDIA_RC6			0x13810C
+#define GEN6_GT_GFX_RC6				_MMIO(0x138108)
+#define VLV_GT_RENDER_RC6			_MMIO(0x138108)
+#define VLV_GT_MEDIA_RC6			_MMIO(0x13810C)
 
-#define GEN6_GT_GFX_RC6p			0x13810C
-#define GEN6_GT_GFX_RC6pp			0x138110
-#define VLV_RENDER_C0_COUNT			0x138118
-#define VLV_MEDIA_C0_COUNT			0x13811C
+#define GEN6_GT_GFX_RC6p			_MMIO(0x13810C)
+#define GEN6_GT_GFX_RC6pp			_MMIO(0x138110)
+#define VLV_RENDER_C0_COUNT			_MMIO(0x138118)
+#define VLV_MEDIA_C0_COUNT			_MMIO(0x13811C)
 
-#define GEN6_PCODE_MAILBOX			0x138124
+#define GEN6_PCODE_MAILBOX			_MMIO(0x138124)
 #define   GEN6_PCODE_READY			(1<<31)
 #define	  GEN6_PCODE_WRITE_RC6VIDS		0x4
 #define	  GEN6_PCODE_READ_RC6VIDS		0x5
@@ -6909,12 +6982,12 @@
 #define   HSW_PCODE_DE_WRITE_FREQ_REQ		0x17
 #define   DISPLAY_IPS_CONTROL			0x19
 #define	  HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL	0x1A
-#define GEN6_PCODE_DATA				0x138128
+#define GEN6_PCODE_DATA				_MMIO(0x138128)
 #define   GEN6_PCODE_FREQ_IA_RATIO_SHIFT	8
 #define   GEN6_PCODE_FREQ_RING_RATIO_SHIFT	16
-#define GEN6_PCODE_DATA1			0x13812C
+#define GEN6_PCODE_DATA1			_MMIO(0x13812C)
 
-#define GEN6_GT_CORE_STATUS		0x138060
+#define GEN6_GT_CORE_STATUS		_MMIO(0x138060)
 #define   GEN6_CORE_CPD_STATE_MASK	(7<<4)
 #define   GEN6_RCn_MASK			7
 #define   GEN6_RC0			0
@@ -6922,26 +6995,26 @@
 #define   GEN6_RC6			3
 #define   GEN6_RC7			4
 
-#define GEN8_GT_SLICE_INFO		0x138064
+#define GEN8_GT_SLICE_INFO		_MMIO(0x138064)
 #define   GEN8_LSLICESTAT_MASK		0x7
 
-#define CHV_POWER_SS0_SIG1		0xa720
-#define CHV_POWER_SS1_SIG1		0xa728
+#define CHV_POWER_SS0_SIG1		_MMIO(0xa720)
+#define CHV_POWER_SS1_SIG1		_MMIO(0xa728)
 #define   CHV_SS_PG_ENABLE		(1<<1)
 #define   CHV_EU08_PG_ENABLE		(1<<9)
 #define   CHV_EU19_PG_ENABLE		(1<<17)
 #define   CHV_EU210_PG_ENABLE		(1<<25)
 
-#define CHV_POWER_SS0_SIG2		0xa724
-#define CHV_POWER_SS1_SIG2		0xa72c
+#define CHV_POWER_SS0_SIG2		_MMIO(0xa724)
+#define CHV_POWER_SS1_SIG2		_MMIO(0xa72c)
 #define   CHV_EU311_PG_ENABLE		(1<<1)
 
-#define GEN9_SLICE_PGCTL_ACK(slice)	(0x804c + (slice)*0x4)
+#define GEN9_SLICE_PGCTL_ACK(slice)	_MMIO(0x804c + (slice)*0x4)
 #define   GEN9_PGCTL_SLICE_ACK		(1 << 0)
 #define   GEN9_PGCTL_SS_ACK(subslice)	(1 << (2 + (subslice)*2))
 
-#define GEN9_SS01_EU_PGCTL_ACK(slice)	(0x805c + (slice)*0x8)
-#define GEN9_SS23_EU_PGCTL_ACK(slice)	(0x8060 + (slice)*0x8)
+#define GEN9_SS01_EU_PGCTL_ACK(slice)	_MMIO(0x805c + (slice)*0x8)
+#define GEN9_SS23_EU_PGCTL_ACK(slice)	_MMIO(0x8060 + (slice)*0x8)
 #define   GEN9_PGCTL_SSA_EU08_ACK	(1 << 0)
 #define   GEN9_PGCTL_SSA_EU19_ACK	(1 << 2)
 #define   GEN9_PGCTL_SSA_EU210_ACK	(1 << 4)
@@ -6951,18 +7024,17 @@
 #define   GEN9_PGCTL_SSB_EU210_ACK	(1 << 12)
 #define   GEN9_PGCTL_SSB_EU311_ACK	(1 << 14)
 
-#define GEN7_MISCCPCTL			(0x9424)
+#define GEN7_MISCCPCTL				_MMIO(0x9424)
 #define   GEN7_DOP_CLOCK_GATE_ENABLE		(1<<0)
 #define   GEN8_DOP_CLOCK_GATE_CFCLK_ENABLE	(1<<2)
 #define   GEN8_DOP_CLOCK_GATE_GUC_ENABLE	(1<<4)
 #define   GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE     (1<<6)
 
-#define GEN8_GARBCNTL                   0xB004
+#define GEN8_GARBCNTL                   _MMIO(0xB004)
 #define   GEN9_GAPS_TSV_CREDIT_DISABLE  (1<<7)
 
 /* IVYBRIDGE DPF */
-#define GEN7_L3CDERRST1			0xB008 /* L3CD Error Status 1 */
-#define HSW_L3CDERRST11			0xB208 /* L3CD Error Status register 1 slice 1 */
+#define GEN7_L3CDERRST1(slice)		_MMIO(0xB008 + (slice) * 0x200) /* L3CD Error Status 1 */
 #define   GEN7_L3CDERRST1_ROW_MASK	(0x7ff<<14)
 #define   GEN7_PARITY_ERROR_VALID	(1<<13)
 #define   GEN7_L3CDERRST1_BANK_MASK	(3<<11)
@@ -6975,119 +7047,102 @@
 		((reg & GEN7_L3CDERRST1_SUBBANK_MASK) >> 8)
 #define   GEN7_L3CDERRST1_ENABLE	(1<<7)
 
-#define GEN7_L3LOG_BASE			0xB070
-#define HSW_L3LOG_BASE_SLICE1		0xB270
+#define GEN7_L3LOG(slice, i)		_MMIO(0xB070 + (slice) * 0x200 + (i) * 4)
 #define GEN7_L3LOG_SIZE			0x80
 
-#define GEN7_HALF_SLICE_CHICKEN1	0xe100 /* IVB GT1 + VLV */
-#define GEN7_HALF_SLICE_CHICKEN1_GT2	0xf100
+#define GEN7_HALF_SLICE_CHICKEN1	_MMIO(0xe100) /* IVB GT1 + VLV */
+#define GEN7_HALF_SLICE_CHICKEN1_GT2	_MMIO(0xf100)
 #define   GEN7_MAX_PS_THREAD_DEP		(8<<12)
 #define   GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE	(1<<10)
 #define   GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE	(1<<4)
 #define   GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE	(1<<3)
 
-#define GEN9_HALF_SLICE_CHICKEN5	0xe188
+#define GEN9_HALF_SLICE_CHICKEN5	_MMIO(0xe188)
 #define   GEN9_DG_MIRROR_FIX_ENABLE	(1<<5)
 #define   GEN9_CCS_TLB_PREFETCH_ENABLE	(1<<3)
 
-#define GEN8_ROW_CHICKEN		0xe4f0
+#define GEN8_ROW_CHICKEN		_MMIO(0xe4f0)
 #define   PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE	(1<<8)
 #define   STALL_DOP_GATING_DISABLE		(1<<5)
 
-#define GEN7_ROW_CHICKEN2		0xe4f4
-#define GEN7_ROW_CHICKEN2_GT2		0xf4f4
+#define GEN7_ROW_CHICKEN2		_MMIO(0xe4f4)
+#define GEN7_ROW_CHICKEN2_GT2		_MMIO(0xf4f4)
 #define   DOP_CLOCK_GATING_DISABLE	(1<<0)
 
-#define HSW_ROW_CHICKEN3		0xe49c
+#define HSW_ROW_CHICKEN3		_MMIO(0xe49c)
 #define  HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE    (1 << 6)
 
-#define HALF_SLICE_CHICKEN2		0xe180
+#define HALF_SLICE_CHICKEN2		_MMIO(0xe180)
 #define   GEN8_ST_PO_DISABLE		(1<<13)
 
-#define HALF_SLICE_CHICKEN3		0xe184
+#define HALF_SLICE_CHICKEN3		_MMIO(0xe184)
 #define   HSW_SAMPLE_C_PERFORMANCE	(1<<9)
 #define   GEN8_CENTROID_PIXEL_OPT_DIS	(1<<8)
 #define   GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC	(1<<5)
 #define   GEN8_SAMPLER_POWER_BYPASS_DIS	(1<<1)
 
-#define GEN9_HALF_SLICE_CHICKEN7	0xe194
+#define GEN9_HALF_SLICE_CHICKEN7	_MMIO(0xe194)
 #define   GEN9_ENABLE_YV12_BUGFIX	(1<<4)
 
 /* Audio */
-#define G4X_AUD_VID_DID			(dev_priv->info.display_mmio_offset + 0x62020)
+#define G4X_AUD_VID_DID			_MMIO(dev_priv->info.display_mmio_offset + 0x62020)
 #define   INTEL_AUDIO_DEVCL		0x808629FB
 #define   INTEL_AUDIO_DEVBLC		0x80862801
 #define   INTEL_AUDIO_DEVCTG		0x80862802
 
-#define G4X_AUD_CNTL_ST			0x620B4
+#define G4X_AUD_CNTL_ST			_MMIO(0x620B4)
 #define   G4X_ELDV_DEVCL_DEVBLC		(1 << 13)
 #define   G4X_ELDV_DEVCTG		(1 << 14)
 #define   G4X_ELD_ADDR_MASK		(0xf << 5)
 #define   G4X_ELD_ACK			(1 << 4)
-#define G4X_HDMIW_HDMIEDID		0x6210C
+#define G4X_HDMIW_HDMIEDID		_MMIO(0x6210C)
 
 #define _IBX_HDMIW_HDMIEDID_A		0xE2050
 #define _IBX_HDMIW_HDMIEDID_B		0xE2150
-#define IBX_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \
-					_IBX_HDMIW_HDMIEDID_A, \
-					_IBX_HDMIW_HDMIEDID_B)
+#define IBX_HDMIW_HDMIEDID(pipe)	_MMIO_PIPE(pipe, _IBX_HDMIW_HDMIEDID_A, \
+						  _IBX_HDMIW_HDMIEDID_B)
 #define _IBX_AUD_CNTL_ST_A		0xE20B4
 #define _IBX_AUD_CNTL_ST_B		0xE21B4
-#define IBX_AUD_CNTL_ST(pipe) _PIPE(pipe, \
-					_IBX_AUD_CNTL_ST_A, \
-					_IBX_AUD_CNTL_ST_B)
+#define IBX_AUD_CNTL_ST(pipe)		_MMIO_PIPE(pipe, _IBX_AUD_CNTL_ST_A, \
+						  _IBX_AUD_CNTL_ST_B)
 #define   IBX_ELD_BUFFER_SIZE_MASK	(0x1f << 10)
 #define   IBX_ELD_ADDRESS_MASK		(0x1f << 5)
 #define   IBX_ELD_ACK			(1 << 4)
-#define IBX_AUD_CNTL_ST2		0xE20C0
+#define IBX_AUD_CNTL_ST2		_MMIO(0xE20C0)
 #define   IBX_CP_READY(port)		((1 << 1) << (((port) - 1) * 4))
 #define   IBX_ELD_VALID(port)		((1 << 0) << (((port) - 1) * 4))
 
 #define _CPT_HDMIW_HDMIEDID_A		0xE5050
 #define _CPT_HDMIW_HDMIEDID_B		0xE5150
-#define CPT_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \
-					_CPT_HDMIW_HDMIEDID_A, \
-					_CPT_HDMIW_HDMIEDID_B)
+#define CPT_HDMIW_HDMIEDID(pipe)	_MMIO_PIPE(pipe, _CPT_HDMIW_HDMIEDID_A, _CPT_HDMIW_HDMIEDID_B)
 #define _CPT_AUD_CNTL_ST_A		0xE50B4
 #define _CPT_AUD_CNTL_ST_B		0xE51B4
-#define CPT_AUD_CNTL_ST(pipe) _PIPE(pipe, \
-					_CPT_AUD_CNTL_ST_A, \
-					_CPT_AUD_CNTL_ST_B)
-#define CPT_AUD_CNTRL_ST2		0xE50C0
+#define CPT_AUD_CNTL_ST(pipe)		_MMIO_PIPE(pipe, _CPT_AUD_CNTL_ST_A, _CPT_AUD_CNTL_ST_B)
+#define CPT_AUD_CNTRL_ST2		_MMIO(0xE50C0)
 
 #define _VLV_HDMIW_HDMIEDID_A		(VLV_DISPLAY_BASE + 0x62050)
 #define _VLV_HDMIW_HDMIEDID_B		(VLV_DISPLAY_BASE + 0x62150)
-#define VLV_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \
-					_VLV_HDMIW_HDMIEDID_A, \
-					_VLV_HDMIW_HDMIEDID_B)
+#define VLV_HDMIW_HDMIEDID(pipe)	_MMIO_PIPE(pipe, _VLV_HDMIW_HDMIEDID_A, _VLV_HDMIW_HDMIEDID_B)
 #define _VLV_AUD_CNTL_ST_A		(VLV_DISPLAY_BASE + 0x620B4)
 #define _VLV_AUD_CNTL_ST_B		(VLV_DISPLAY_BASE + 0x621B4)
-#define VLV_AUD_CNTL_ST(pipe) _PIPE(pipe, \
-					_VLV_AUD_CNTL_ST_A, \
-					_VLV_AUD_CNTL_ST_B)
-#define VLV_AUD_CNTL_ST2		(VLV_DISPLAY_BASE + 0x620C0)
+#define VLV_AUD_CNTL_ST(pipe)		_MMIO_PIPE(pipe, _VLV_AUD_CNTL_ST_A, _VLV_AUD_CNTL_ST_B)
+#define VLV_AUD_CNTL_ST2		_MMIO(VLV_DISPLAY_BASE + 0x620C0)
 
 /* These are the 4 32-bit write offset registers for each stream
  * output buffer.  It determines the offset from the
  * 3DSTATE_SO_BUFFERs that the next streamed vertex output goes to.
  */
-#define GEN7_SO_WRITE_OFFSET(n)		(0x5280 + (n) * 4)
+#define GEN7_SO_WRITE_OFFSET(n)		_MMIO(0x5280 + (n) * 4)
 
 #define _IBX_AUD_CONFIG_A		0xe2000
 #define _IBX_AUD_CONFIG_B		0xe2100
-#define IBX_AUD_CFG(pipe) _PIPE(pipe, \
-					_IBX_AUD_CONFIG_A, \
-					_IBX_AUD_CONFIG_B)
+#define IBX_AUD_CFG(pipe)		_MMIO_PIPE(pipe, _IBX_AUD_CONFIG_A, _IBX_AUD_CONFIG_B)
 #define _CPT_AUD_CONFIG_A		0xe5000
 #define _CPT_AUD_CONFIG_B		0xe5100
-#define CPT_AUD_CFG(pipe) _PIPE(pipe, \
-					_CPT_AUD_CONFIG_A, \
-					_CPT_AUD_CONFIG_B)
+#define CPT_AUD_CFG(pipe)		_MMIO_PIPE(pipe, _CPT_AUD_CONFIG_A, _CPT_AUD_CONFIG_B)
 #define _VLV_AUD_CONFIG_A		(VLV_DISPLAY_BASE + 0x62000)
 #define _VLV_AUD_CONFIG_B		(VLV_DISPLAY_BASE + 0x62100)
-#define VLV_AUD_CFG(pipe) _PIPE(pipe, \
-					_VLV_AUD_CONFIG_A, \
-					_VLV_AUD_CONFIG_B)
+#define VLV_AUD_CFG(pipe)		_MMIO_PIPE(pipe, _VLV_AUD_CONFIG_A, _VLV_AUD_CONFIG_B)
 
 #define   AUD_CONFIG_N_VALUE_INDEX		(1 << 29)
 #define   AUD_CONFIG_N_PROG_ENABLE		(1 << 28)
@@ -7112,72 +7167,62 @@
 /* HSW Audio */
 #define _HSW_AUD_CONFIG_A		0x65000
 #define _HSW_AUD_CONFIG_B		0x65100
-#define HSW_AUD_CFG(pipe) _PIPE(pipe, \
-					_HSW_AUD_CONFIG_A, \
-					_HSW_AUD_CONFIG_B)
+#define HSW_AUD_CFG(pipe)		_MMIO_PIPE(pipe, _HSW_AUD_CONFIG_A, _HSW_AUD_CONFIG_B)
 
 #define _HSW_AUD_MISC_CTRL_A		0x65010
 #define _HSW_AUD_MISC_CTRL_B		0x65110
-#define HSW_AUD_MISC_CTRL(pipe) _PIPE(pipe, \
-					_HSW_AUD_MISC_CTRL_A, \
-					_HSW_AUD_MISC_CTRL_B)
+#define HSW_AUD_MISC_CTRL(pipe)		_MMIO_PIPE(pipe, _HSW_AUD_MISC_CTRL_A, _HSW_AUD_MISC_CTRL_B)
 
 #define _HSW_AUD_DIP_ELD_CTRL_ST_A	0x650b4
 #define _HSW_AUD_DIP_ELD_CTRL_ST_B	0x651b4
-#define HSW_AUD_DIP_ELD_CTRL(pipe) _PIPE(pipe, \
-					_HSW_AUD_DIP_ELD_CTRL_ST_A, \
-					_HSW_AUD_DIP_ELD_CTRL_ST_B)
+#define HSW_AUD_DIP_ELD_CTRL(pipe)	_MMIO_PIPE(pipe, _HSW_AUD_DIP_ELD_CTRL_ST_A, _HSW_AUD_DIP_ELD_CTRL_ST_B)
 
 /* Audio Digital Converter */
 #define _HSW_AUD_DIG_CNVT_1		0x65080
 #define _HSW_AUD_DIG_CNVT_2		0x65180
-#define AUD_DIG_CNVT(pipe) _PIPE(pipe, \
-					_HSW_AUD_DIG_CNVT_1, \
-					_HSW_AUD_DIG_CNVT_2)
+#define AUD_DIG_CNVT(pipe)		_MMIO_PIPE(pipe, _HSW_AUD_DIG_CNVT_1, _HSW_AUD_DIG_CNVT_2)
 #define DIP_PORT_SEL_MASK		0x3
 
 #define _HSW_AUD_EDID_DATA_A		0x65050
 #define _HSW_AUD_EDID_DATA_B		0x65150
-#define HSW_AUD_EDID_DATA(pipe) _PIPE(pipe, \
-					_HSW_AUD_EDID_DATA_A, \
-					_HSW_AUD_EDID_DATA_B)
+#define HSW_AUD_EDID_DATA(pipe)		_MMIO_PIPE(pipe, _HSW_AUD_EDID_DATA_A, _HSW_AUD_EDID_DATA_B)
 
-#define HSW_AUD_PIPE_CONV_CFG		0x6507c
-#define HSW_AUD_PIN_ELD_CP_VLD		0x650c0
+#define HSW_AUD_PIPE_CONV_CFG		_MMIO(0x6507c)
+#define HSW_AUD_PIN_ELD_CP_VLD		_MMIO(0x650c0)
 #define   AUDIO_INACTIVE(trans)		((1 << 3) << ((trans) * 4))
 #define   AUDIO_OUTPUT_ENABLE(trans)	((1 << 2) << ((trans) * 4))
 #define   AUDIO_CP_READY(trans)		((1 << 1) << ((trans) * 4))
 #define   AUDIO_ELD_VALID(trans)	((1 << 0) << ((trans) * 4))
 
-#define HSW_AUD_CHICKENBIT			0x65f10
+#define HSW_AUD_CHICKENBIT			_MMIO(0x65f10)
 #define   SKL_AUD_CODEC_WAKE_SIGNAL		(1 << 15)
 
 /* HSW Power Wells */
-#define HSW_PWR_WELL_BIOS			0x45400 /* CTL1 */
-#define HSW_PWR_WELL_DRIVER			0x45404 /* CTL2 */
-#define HSW_PWR_WELL_KVMR			0x45408 /* CTL3 */
-#define HSW_PWR_WELL_DEBUG			0x4540C /* CTL4 */
+#define HSW_PWR_WELL_BIOS			_MMIO(0x45400) /* CTL1 */
+#define HSW_PWR_WELL_DRIVER			_MMIO(0x45404) /* CTL2 */
+#define HSW_PWR_WELL_KVMR			_MMIO(0x45408) /* CTL3 */
+#define HSW_PWR_WELL_DEBUG			_MMIO(0x4540C) /* CTL4 */
 #define   HSW_PWR_WELL_ENABLE_REQUEST		(1<<31)
 #define   HSW_PWR_WELL_STATE_ENABLED		(1<<30)
-#define HSW_PWR_WELL_CTL5			0x45410
+#define HSW_PWR_WELL_CTL5			_MMIO(0x45410)
 #define   HSW_PWR_WELL_ENABLE_SINGLE_STEP	(1<<31)
 #define   HSW_PWR_WELL_PWR_GATE_OVERRIDE	(1<<20)
 #define   HSW_PWR_WELL_FORCE_ON			(1<<19)
-#define HSW_PWR_WELL_CTL6			0x45414
+#define HSW_PWR_WELL_CTL6			_MMIO(0x45414)
 
 /* SKL Fuse Status */
-#define SKL_FUSE_STATUS				0x42000
+#define SKL_FUSE_STATUS				_MMIO(0x42000)
 #define  SKL_FUSE_DOWNLOAD_STATUS              (1<<31)
 #define  SKL_FUSE_PG0_DIST_STATUS              (1<<27)
 #define  SKL_FUSE_PG1_DIST_STATUS              (1<<26)
 #define  SKL_FUSE_PG2_DIST_STATUS              (1<<25)
 
 /* Per-pipe DDI Function Control */
-#define TRANS_DDI_FUNC_CTL_A		0x60400
-#define TRANS_DDI_FUNC_CTL_B		0x61400
-#define TRANS_DDI_FUNC_CTL_C		0x62400
-#define TRANS_DDI_FUNC_CTL_EDP		0x6F400
-#define TRANS_DDI_FUNC_CTL(tran) _TRANSCODER2(tran, TRANS_DDI_FUNC_CTL_A)
+#define _TRANS_DDI_FUNC_CTL_A		0x60400
+#define _TRANS_DDI_FUNC_CTL_B		0x61400
+#define _TRANS_DDI_FUNC_CTL_C		0x62400
+#define _TRANS_DDI_FUNC_CTL_EDP		0x6F400
+#define TRANS_DDI_FUNC_CTL(tran) _MMIO_TRANS2(tran, _TRANS_DDI_FUNC_CTL_A)
 
 #define  TRANS_DDI_FUNC_ENABLE		(1<<31)
 /* Those bits are ignored by pipe EDP since it can only connect to DDI A */
@@ -7207,9 +7252,9 @@
 #define  TRANS_DDI_BFI_ENABLE		(1<<4)
 
 /* DisplayPort Transport Control */
-#define DP_TP_CTL_A			0x64040
-#define DP_TP_CTL_B			0x64140
-#define DP_TP_CTL(port) _PORT(port, DP_TP_CTL_A, DP_TP_CTL_B)
+#define _DP_TP_CTL_A			0x64040
+#define _DP_TP_CTL_B			0x64140
+#define DP_TP_CTL(port) _MMIO_PORT(port, _DP_TP_CTL_A, _DP_TP_CTL_B)
 #define  DP_TP_CTL_ENABLE			(1<<31)
 #define  DP_TP_CTL_MODE_SST			(0<<27)
 #define  DP_TP_CTL_MODE_MST			(1<<27)
@@ -7225,9 +7270,9 @@
 #define  DP_TP_CTL_SCRAMBLE_DISABLE		(1<<7)
 
 /* DisplayPort Transport Status */
-#define DP_TP_STATUS_A			0x64044
-#define DP_TP_STATUS_B			0x64144
-#define DP_TP_STATUS(port) _PORT(port, DP_TP_STATUS_A, DP_TP_STATUS_B)
+#define _DP_TP_STATUS_A			0x64044
+#define _DP_TP_STATUS_B			0x64144
+#define DP_TP_STATUS(port) _MMIO_PORT(port, _DP_TP_STATUS_A, _DP_TP_STATUS_B)
 #define  DP_TP_STATUS_IDLE_DONE			(1<<25)
 #define  DP_TP_STATUS_ACT_SENT			(1<<24)
 #define  DP_TP_STATUS_MODE_STATUS_MST		(1<<23)
@@ -7237,9 +7282,9 @@
 #define  DP_TP_STATUS_PAYLOAD_MAPPING_VC0	(3 << 0)
 
 /* DDI Buffer Control */
-#define DDI_BUF_CTL_A				0x64000
-#define DDI_BUF_CTL_B				0x64100
-#define DDI_BUF_CTL(port) _PORT(port, DDI_BUF_CTL_A, DDI_BUF_CTL_B)
+#define _DDI_BUF_CTL_A				0x64000
+#define _DDI_BUF_CTL_B				0x64100
+#define DDI_BUF_CTL(port) _MMIO_PORT(port, _DDI_BUF_CTL_A, _DDI_BUF_CTL_B)
 #define  DDI_BUF_CTL_ENABLE			(1<<31)
 #define  DDI_BUF_TRANS_SELECT(n)	((n) << 24)
 #define  DDI_BUF_EMP_MASK			(0xf<<24)
@@ -7252,17 +7297,17 @@
 #define  DDI_INIT_DISPLAY_DETECTED		(1<<0)
 
 /* DDI Buffer Translations */
-#define DDI_BUF_TRANS_A				0x64E00
-#define DDI_BUF_TRANS_B				0x64E60
-#define DDI_BUF_TRANS_LO(port, i) (_PORT(port, DDI_BUF_TRANS_A, DDI_BUF_TRANS_B) + (i) * 8)
-#define DDI_BUF_TRANS_HI(port, i) (_PORT(port, DDI_BUF_TRANS_A, DDI_BUF_TRANS_B) + (i) * 8 + 4)
+#define _DDI_BUF_TRANS_A		0x64E00
+#define _DDI_BUF_TRANS_B		0x64E60
+#define DDI_BUF_TRANS_LO(port, i)	_MMIO(_PORT(port, _DDI_BUF_TRANS_A, _DDI_BUF_TRANS_B) + (i) * 8)
+#define DDI_BUF_TRANS_HI(port, i)	_MMIO(_PORT(port, _DDI_BUF_TRANS_A, _DDI_BUF_TRANS_B) + (i) * 8 + 4)
 
 /* Sideband Interface (SBI) is programmed indirectly, via
  * SBI_ADDR, which contains the register offset; and SBI_DATA,
  * which contains the payload */
-#define SBI_ADDR			0xC6000
-#define SBI_DATA			0xC6004
-#define SBI_CTL_STAT			0xC6008
+#define SBI_ADDR			_MMIO(0xC6000)
+#define SBI_DATA			_MMIO(0xC6004)
+#define SBI_CTL_STAT			_MMIO(0xC6008)
 #define  SBI_CTL_DEST_ICLK		(0x0<<16)
 #define  SBI_CTL_DEST_MPHY		(0x1<<16)
 #define  SBI_CTL_OP_IORD		(0x2<<8)
@@ -7293,12 +7338,12 @@
 #define   SBI_GEN0_CFG_BUFFENABLE_DISABLE	(1<<0)
 
 /* LPT PIXCLK_GATE */
-#define PIXCLK_GATE			0xC6020
+#define PIXCLK_GATE			_MMIO(0xC6020)
 #define  PIXCLK_GATE_UNGATE		(1<<0)
 #define  PIXCLK_GATE_GATE		(0<<0)
 
 /* SPLL */
-#define SPLL_CTL			0x46020
+#define SPLL_CTL			_MMIO(0x46020)
 #define  SPLL_PLL_ENABLE		(1<<31)
 #define  SPLL_PLL_SSC			(1<<28)
 #define  SPLL_PLL_NON_SSC		(2<<28)
@@ -7310,9 +7355,9 @@
 #define  SPLL_PLL_FREQ_MASK		(3<<26)
 
 /* WRPLL */
-#define WRPLL_CTL1			0x46040
-#define WRPLL_CTL2			0x46060
-#define WRPLL_CTL(pll)			(pll == 0 ? WRPLL_CTL1 : WRPLL_CTL2)
+#define _WRPLL_CTL1			0x46040
+#define _WRPLL_CTL2			0x46060
+#define WRPLL_CTL(pll)			_MMIO_PIPE(pll, _WRPLL_CTL1, _WRPLL_CTL2)
 #define  WRPLL_PLL_ENABLE		(1<<31)
 #define  WRPLL_PLL_SSC			(1<<28)
 #define  WRPLL_PLL_NON_SSC		(2<<28)
@@ -7329,9 +7374,9 @@
 #define  WRPLL_DIVIDER_FB_MASK		(0xff<<16)
 
 /* Port clock selection */
-#define PORT_CLK_SEL_A			0x46100
-#define PORT_CLK_SEL_B			0x46104
-#define PORT_CLK_SEL(port) _PORT(port, PORT_CLK_SEL_A, PORT_CLK_SEL_B)
+#define _PORT_CLK_SEL_A			0x46100
+#define _PORT_CLK_SEL_B			0x46104
+#define PORT_CLK_SEL(port) _MMIO_PORT(port, _PORT_CLK_SEL_A, _PORT_CLK_SEL_B)
 #define  PORT_CLK_SEL_LCPLL_2700	(0<<29)
 #define  PORT_CLK_SEL_LCPLL_1350	(1<<29)
 #define  PORT_CLK_SEL_LCPLL_810		(2<<29)
@@ -7343,18 +7388,18 @@
 #define  PORT_CLK_SEL_MASK		(7<<29)
 
 /* Transcoder clock selection */
-#define TRANS_CLK_SEL_A			0x46140
-#define TRANS_CLK_SEL_B			0x46144
-#define TRANS_CLK_SEL(tran) _TRANSCODER(tran, TRANS_CLK_SEL_A, TRANS_CLK_SEL_B)
+#define _TRANS_CLK_SEL_A		0x46140
+#define _TRANS_CLK_SEL_B		0x46144
+#define TRANS_CLK_SEL(tran) _MMIO_TRANS(tran, _TRANS_CLK_SEL_A, _TRANS_CLK_SEL_B)
 /* For each transcoder, we need to select the corresponding port clock */
 #define  TRANS_CLK_SEL_DISABLED		(0x0<<29)
 #define  TRANS_CLK_SEL_PORT(x)		(((x)+1)<<29)
 
-#define TRANSA_MSA_MISC			0x60410
-#define TRANSB_MSA_MISC			0x61410
-#define TRANSC_MSA_MISC			0x62410
-#define TRANS_EDP_MSA_MISC		0x6f410
-#define TRANS_MSA_MISC(tran) _TRANSCODER2(tran, TRANSA_MSA_MISC)
+#define _TRANSA_MSA_MISC		0x60410
+#define _TRANSB_MSA_MISC		0x61410
+#define _TRANSC_MSA_MISC		0x62410
+#define _TRANS_EDP_MSA_MISC		0x6f410
+#define TRANS_MSA_MISC(tran) _MMIO_TRANS2(tran, _TRANSA_MSA_MISC)
 
 #define  TRANS_MSA_SYNC_CLK		(1<<0)
 #define  TRANS_MSA_6_BPC		(0<<5)
@@ -7364,7 +7409,7 @@
 #define  TRANS_MSA_16_BPC		(4<<5)
 
 /* LCPLL Control */
-#define LCPLL_CTL			0x130040
+#define LCPLL_CTL			_MMIO(0x130040)
 #define  LCPLL_PLL_DISABLE		(1<<31)
 #define  LCPLL_PLL_LOCK			(1<<30)
 #define  LCPLL_CLK_FREQ_MASK		(3<<26)
@@ -7384,7 +7429,7 @@
  */
 
 /* CDCLK_CTL */
-#define CDCLK_CTL			0x46000
+#define CDCLK_CTL			_MMIO(0x46000)
 #define  CDCLK_FREQ_SEL_MASK		(3<<26)
 #define  CDCLK_FREQ_450_432		(0<<26)
 #define  CDCLK_FREQ_540			(1<<26)
@@ -7400,12 +7445,12 @@
 #define  BXT_CDCLK_SSA_PRECHARGE_ENABLE	(1<<16)
 
 /* LCPLL_CTL */
-#define LCPLL1_CTL		0x46010
-#define LCPLL2_CTL		0x46014
+#define LCPLL1_CTL		_MMIO(0x46010)
+#define LCPLL2_CTL		_MMIO(0x46014)
 #define  LCPLL_PLL_ENABLE	(1<<31)
 
 /* DPLL control1 */
-#define DPLL_CTRL1		0x6C058
+#define DPLL_CTRL1		_MMIO(0x6C058)
 #define  DPLL_CTRL1_HDMI_MODE(id)		(1<<((id)*6+5))
 #define  DPLL_CTRL1_SSC(id)			(1<<((id)*6+4))
 #define  DPLL_CTRL1_LINK_RATE_MASK(id)		(7<<((id)*6+1))
@@ -7420,7 +7465,7 @@
 #define  DPLL_CTRL1_LINK_RATE_2160		5
 
 /* DPLL control2 */
-#define DPLL_CTRL2				0x6C05C
+#define DPLL_CTRL2				_MMIO(0x6C05C)
 #define  DPLL_CTRL2_DDI_CLK_OFF(port)		(1<<((port)+15))
 #define  DPLL_CTRL2_DDI_CLK_SEL_MASK(port)	(3<<((port)*3+1))
 #define  DPLL_CTRL2_DDI_CLK_SEL_SHIFT(port)    ((port)*3+1)
@@ -7428,21 +7473,21 @@
 #define  DPLL_CTRL2_DDI_SEL_OVERRIDE(port)     (1<<((port)*3))
 
 /* DPLL Status */
-#define DPLL_STATUS	0x6C060
+#define DPLL_STATUS	_MMIO(0x6C060)
 #define  DPLL_LOCK(id) (1<<((id)*8))
 
 /* DPLL cfg */
-#define DPLL1_CFGCR1	0x6C040
-#define DPLL2_CFGCR1	0x6C048
-#define DPLL3_CFGCR1	0x6C050
+#define _DPLL1_CFGCR1	0x6C040
+#define _DPLL2_CFGCR1	0x6C048
+#define _DPLL3_CFGCR1	0x6C050
 #define  DPLL_CFGCR1_FREQ_ENABLE	(1<<31)
 #define  DPLL_CFGCR1_DCO_FRACTION_MASK	(0x7fff<<9)
 #define  DPLL_CFGCR1_DCO_FRACTION(x)	((x)<<9)
 #define  DPLL_CFGCR1_DCO_INTEGER_MASK	(0x1ff)
 
-#define DPLL1_CFGCR2	0x6C044
-#define DPLL2_CFGCR2	0x6C04C
-#define DPLL3_CFGCR2	0x6C054
+#define _DPLL1_CFGCR2	0x6C044
+#define _DPLL2_CFGCR2	0x6C04C
+#define _DPLL3_CFGCR2	0x6C054
 #define  DPLL_CFGCR2_QDIV_RATIO_MASK	(0xff<<8)
 #define  DPLL_CFGCR2_QDIV_RATIO(x)	((x)<<8)
 #define  DPLL_CFGCR2_QDIV_MODE(x)	((x)<<7)
@@ -7460,58 +7505,58 @@
 #define  DPLL_CFGCR2_PDIV_7 (4<<2)
 #define  DPLL_CFGCR2_CENTRAL_FREQ_MASK	(3)
 
-#define DPLL_CFGCR1(id) (DPLL1_CFGCR1 + ((id) - SKL_DPLL1) * 8)
-#define DPLL_CFGCR2(id) (DPLL1_CFGCR2 + ((id) - SKL_DPLL1) * 8)
+#define DPLL_CFGCR1(id)	_MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR1, _DPLL2_CFGCR2)
+#define DPLL_CFGCR2(id)	_MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR2, _DPLL2_CFGCR2)
 
 /* BXT display engine PLL */
-#define BXT_DE_PLL_CTL			0x6d000
+#define BXT_DE_PLL_CTL			_MMIO(0x6d000)
 #define   BXT_DE_PLL_RATIO(x)		(x)	/* {60,65,100} * 19.2MHz */
 #define   BXT_DE_PLL_RATIO_MASK		0xff
 
-#define BXT_DE_PLL_ENABLE		0x46070
+#define BXT_DE_PLL_ENABLE		_MMIO(0x46070)
 #define   BXT_DE_PLL_PLL_ENABLE		(1 << 31)
 #define   BXT_DE_PLL_LOCK		(1 << 30)
 
 /* GEN9 DC */
-#define DC_STATE_EN			0x45504
+#define DC_STATE_EN			_MMIO(0x45504)
+#define  DC_STATE_DISABLE		0
 #define  DC_STATE_EN_UPTO_DC5		(1<<0)
 #define  DC_STATE_EN_DC9		(1<<3)
 #define  DC_STATE_EN_UPTO_DC6		(2<<0)
 #define  DC_STATE_EN_UPTO_DC5_DC6_MASK   0x3
 
-#define  DC_STATE_DEBUG                  0x45520
+#define  DC_STATE_DEBUG                  _MMIO(0x45520)
 #define  DC_STATE_DEBUG_MASK_MEMORY_UP	(1<<1)
 
 /* Please see hsw_read_dcomp() and hsw_write_dcomp() before using this register,
  * since on HSW we can't write to it using I915_WRITE. */
-#define D_COMP_HSW			(MCHBAR_MIRROR_BASE_SNB + 0x5F0C)
-#define D_COMP_BDW			0x138144
+#define D_COMP_HSW			_MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5F0C)
+#define D_COMP_BDW			_MMIO(0x138144)
 #define  D_COMP_RCOMP_IN_PROGRESS	(1<<9)
 #define  D_COMP_COMP_FORCE		(1<<8)
 #define  D_COMP_COMP_DISABLE		(1<<0)
 
 /* Pipe WM_LINETIME - watermark line time */
-#define PIPE_WM_LINETIME_A		0x45270
-#define PIPE_WM_LINETIME_B		0x45274
-#define PIPE_WM_LINETIME(pipe) _PIPE(pipe, PIPE_WM_LINETIME_A, \
-					   PIPE_WM_LINETIME_B)
+#define _PIPE_WM_LINETIME_A		0x45270
+#define _PIPE_WM_LINETIME_B		0x45274
+#define PIPE_WM_LINETIME(pipe) _MMIO_PIPE(pipe, _PIPE_WM_LINETIME_A, _PIPE_WM_LINETIME_B)
 #define   PIPE_WM_LINETIME_MASK			(0x1ff)
 #define   PIPE_WM_LINETIME_TIME(x)		((x))
 #define   PIPE_WM_LINETIME_IPS_LINETIME_MASK	(0x1ff<<16)
 #define   PIPE_WM_LINETIME_IPS_LINETIME(x)	((x)<<16)
 
 /* SFUSE_STRAP */
-#define SFUSE_STRAP			0xc2014
+#define SFUSE_STRAP			_MMIO(0xc2014)
 #define  SFUSE_STRAP_FUSE_LOCK		(1<<13)
 #define  SFUSE_STRAP_DISPLAY_DISABLED	(1<<7)
 #define  SFUSE_STRAP_DDIB_DETECTED	(1<<2)
 #define  SFUSE_STRAP_DDIC_DETECTED	(1<<1)
 #define  SFUSE_STRAP_DDID_DETECTED	(1<<0)
 
-#define WM_MISC				0x45260
+#define WM_MISC				_MMIO(0x45260)
 #define  WM_MISC_DATA_PARTITION_5_6	(1 << 0)
 
-#define WM_DBG				0x45280
+#define WM_DBG				_MMIO(0x45280)
 #define  WM_DBG_DISALLOW_MULTIPLE_LP	(1<<0)
 #define  WM_DBG_DISALLOW_MAXFIFO	(1<<1)
 #define  WM_DBG_DISALLOW_SPRITE		(1<<2)
@@ -7548,28 +7593,29 @@
 #define _PIPE_B_CSC_POSTOFF_ME	0x49144
 #define _PIPE_B_CSC_POSTOFF_LO	0x49148
 
-#define PIPE_CSC_COEFF_RY_GY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY)
-#define PIPE_CSC_COEFF_BY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY)
-#define PIPE_CSC_COEFF_RU_GU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU)
-#define PIPE_CSC_COEFF_BU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU)
-#define PIPE_CSC_COEFF_RV_GV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RV_GV, _PIPE_B_CSC_COEFF_RV_GV)
-#define PIPE_CSC_COEFF_BV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BV, _PIPE_B_CSC_COEFF_BV)
-#define PIPE_CSC_MODE(pipe) _PIPE(pipe, _PIPE_A_CSC_MODE, _PIPE_B_CSC_MODE)
-#define PIPE_CSC_PREOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_HI, _PIPE_B_CSC_PREOFF_HI)
-#define PIPE_CSC_PREOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME)
-#define PIPE_CSC_PREOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO)
-#define PIPE_CSC_POSTOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI)
-#define PIPE_CSC_POSTOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME)
-#define PIPE_CSC_POSTOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO)
+#define PIPE_CSC_COEFF_RY_GY(pipe)	_MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY)
+#define PIPE_CSC_COEFF_BY(pipe)		_MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY)
+#define PIPE_CSC_COEFF_RU_GU(pipe)	_MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU)
+#define PIPE_CSC_COEFF_BU(pipe)		_MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU)
+#define PIPE_CSC_COEFF_RV_GV(pipe)	_MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RV_GV, _PIPE_B_CSC_COEFF_RV_GV)
+#define PIPE_CSC_COEFF_BV(pipe)		_MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BV, _PIPE_B_CSC_COEFF_BV)
+#define PIPE_CSC_MODE(pipe)		_MMIO_PIPE(pipe, _PIPE_A_CSC_MODE, _PIPE_B_CSC_MODE)
+#define PIPE_CSC_PREOFF_HI(pipe)	_MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_HI, _PIPE_B_CSC_PREOFF_HI)
+#define PIPE_CSC_PREOFF_ME(pipe)	_MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME)
+#define PIPE_CSC_PREOFF_LO(pipe)	_MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO)
+#define PIPE_CSC_POSTOFF_HI(pipe)	_MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI)
+#define PIPE_CSC_POSTOFF_ME(pipe)	_MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME)
+#define PIPE_CSC_POSTOFF_LO(pipe)	_MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO)
 
 /* MIPI DSI registers */
 
 #define _MIPI_PORT(port, a, c)	_PORT3(port, a, 0, c)	/* ports A and C only */
+#define _MMIO_MIPI(port, a, c)	_MMIO(_MIPI_PORT(port, a, c))
 
 /* BXT MIPI clock controls */
 #define BXT_MAX_VAR_OUTPUT_KHZ			39500
 
-#define BXT_MIPI_CLOCK_CTL			0x46090
+#define BXT_MIPI_CLOCK_CTL			_MMIO(0x46090)
 #define  BXT_MIPI1_DIV_SHIFT			26
 #define  BXT_MIPI2_DIV_SHIFT			10
 #define  BXT_MIPI_DIV_SHIFT(port)		\
@@ -7631,20 +7677,20 @@
 /* BXT MIPI mode configure */
 #define  _BXT_MIPIA_TRANS_HACTIVE			0x6B0F8
 #define  _BXT_MIPIC_TRANS_HACTIVE			0x6B8F8
-#define  BXT_MIPI_TRANS_HACTIVE(tc)	_MIPI_PORT(tc, \
+#define  BXT_MIPI_TRANS_HACTIVE(tc)	_MMIO_MIPI(tc, \
 		_BXT_MIPIA_TRANS_HACTIVE, _BXT_MIPIC_TRANS_HACTIVE)
 
 #define  _BXT_MIPIA_TRANS_VACTIVE			0x6B0FC
 #define  _BXT_MIPIC_TRANS_VACTIVE			0x6B8FC
-#define  BXT_MIPI_TRANS_VACTIVE(tc)	_MIPI_PORT(tc, \
+#define  BXT_MIPI_TRANS_VACTIVE(tc)	_MMIO_MIPI(tc, \
 		_BXT_MIPIA_TRANS_VACTIVE, _BXT_MIPIC_TRANS_VACTIVE)
 
 #define  _BXT_MIPIA_TRANS_VTOTAL			0x6B100
 #define  _BXT_MIPIC_TRANS_VTOTAL			0x6B900
-#define  BXT_MIPI_TRANS_VTOTAL(tc)	_MIPI_PORT(tc, \
+#define  BXT_MIPI_TRANS_VTOTAL(tc)	_MMIO_MIPI(tc, \
 		_BXT_MIPIA_TRANS_VTOTAL, _BXT_MIPIC_TRANS_VTOTAL)
 
-#define BXT_DSI_PLL_CTL			0x161000
+#define BXT_DSI_PLL_CTL			_MMIO(0x161000)
 #define  BXT_DSI_PLL_PVD_RATIO_SHIFT	16
 #define  BXT_DSI_PLL_PVD_RATIO_MASK	(3 << BXT_DSI_PLL_PVD_RATIO_SHIFT)
 #define  BXT_DSI_PLL_PVD_RATIO_1	(1 << BXT_DSI_PLL_PVD_RATIO_SHIFT)
@@ -7662,19 +7708,18 @@
 #define BXT_DSI_PLL_RATIO_MASK		0xFF
 #define BXT_REF_CLOCK_KHZ		19500
 
-#define BXT_DSI_PLL_ENABLE		0x46080
+#define BXT_DSI_PLL_ENABLE		_MMIO(0x46080)
 #define  BXT_DSI_PLL_DO_ENABLE		(1 << 31)
 #define  BXT_DSI_PLL_LOCKED		(1 << 30)
 
 #define _MIPIA_PORT_CTRL			(VLV_DISPLAY_BASE + 0x61190)
 #define _MIPIC_PORT_CTRL			(VLV_DISPLAY_BASE + 0x61700)
-#define MIPI_PORT_CTRL(port)	_MIPI_PORT(port, _MIPIA_PORT_CTRL, _MIPIC_PORT_CTRL)
+#define MIPI_PORT_CTRL(port)	_MMIO_MIPI(port, _MIPIA_PORT_CTRL, _MIPIC_PORT_CTRL)
 
  /* BXT port control */
 #define _BXT_MIPIA_PORT_CTRL				0x6B0C0
 #define _BXT_MIPIC_PORT_CTRL				0x6B8C0
-#define BXT_MIPI_PORT_CTRL(tc)	_MIPI_PORT(tc, _BXT_MIPIA_PORT_CTRL, \
-						_BXT_MIPIC_PORT_CTRL)
+#define BXT_MIPI_PORT_CTRL(tc)	_MMIO_MIPI(tc, _BXT_MIPIA_PORT_CTRL, _BXT_MIPIC_PORT_CTRL)
 
 #define  DPI_ENABLE					(1 << 31) /* A + C */
 #define  MIPIA_MIPI4DPHY_DELAY_COUNT_SHIFT		27
@@ -7718,8 +7763,7 @@
 
 #define _MIPIA_TEARING_CTRL			(VLV_DISPLAY_BASE + 0x61194)
 #define _MIPIC_TEARING_CTRL			(VLV_DISPLAY_BASE + 0x61704)
-#define MIPI_TEARING_CTRL(port)			_MIPI_PORT(port, \
-				_MIPIA_TEARING_CTRL, _MIPIC_TEARING_CTRL)
+#define MIPI_TEARING_CTRL(port)			_MMIO_MIPI(port, _MIPIA_TEARING_CTRL, _MIPIC_TEARING_CTRL)
 #define  TEARING_EFFECT_DELAY_SHIFT			0
 #define  TEARING_EFFECT_DELAY_MASK			(0xffff << 0)
 
@@ -7730,8 +7774,7 @@
 
 #define _MIPIA_DEVICE_READY		(dev_priv->mipi_mmio_base + 0xb000)
 #define _MIPIC_DEVICE_READY		(dev_priv->mipi_mmio_base + 0xb800)
-#define MIPI_DEVICE_READY(port)		_MIPI_PORT(port, _MIPIA_DEVICE_READY, \
-						_MIPIC_DEVICE_READY)
+#define MIPI_DEVICE_READY(port)		_MMIO_MIPI(port, _MIPIA_DEVICE_READY, _MIPIC_DEVICE_READY)
 #define  BUS_POSSESSION					(1 << 3) /* set to give bus to receiver */
 #define  ULPS_STATE_MASK				(3 << 1)
 #define  ULPS_STATE_ENTER				(2 << 1)
@@ -7741,12 +7784,10 @@
 
 #define _MIPIA_INTR_STAT		(dev_priv->mipi_mmio_base + 0xb004)
 #define _MIPIC_INTR_STAT		(dev_priv->mipi_mmio_base + 0xb804)
-#define MIPI_INTR_STAT(port)		_MIPI_PORT(port, _MIPIA_INTR_STAT, \
-					_MIPIC_INTR_STAT)
+#define MIPI_INTR_STAT(port)		_MMIO_MIPI(port, _MIPIA_INTR_STAT, _MIPIC_INTR_STAT)
 #define _MIPIA_INTR_EN			(dev_priv->mipi_mmio_base + 0xb008)
 #define _MIPIC_INTR_EN			(dev_priv->mipi_mmio_base + 0xb808)
-#define MIPI_INTR_EN(port)		_MIPI_PORT(port, _MIPIA_INTR_EN, \
-					_MIPIC_INTR_EN)
+#define MIPI_INTR_EN(port)		_MMIO_MIPI(port, _MIPIA_INTR_EN, _MIPIC_INTR_EN)
 #define  TEARING_EFFECT					(1 << 31)
 #define  SPL_PKT_SENT_INTERRUPT				(1 << 30)
 #define  GEN_READ_DATA_AVAIL				(1 << 29)
@@ -7782,8 +7823,7 @@
 
 #define _MIPIA_DSI_FUNC_PRG		(dev_priv->mipi_mmio_base + 0xb00c)
 #define _MIPIC_DSI_FUNC_PRG		(dev_priv->mipi_mmio_base + 0xb80c)
-#define MIPI_DSI_FUNC_PRG(port)		_MIPI_PORT(port, _MIPIA_DSI_FUNC_PRG, \
-						_MIPIC_DSI_FUNC_PRG)
+#define MIPI_DSI_FUNC_PRG(port)		_MMIO_MIPI(port, _MIPIA_DSI_FUNC_PRG, _MIPIC_DSI_FUNC_PRG)
 #define  CMD_MODE_DATA_WIDTH_MASK			(7 << 13)
 #define  CMD_MODE_NOT_SUPPORTED				(0 << 13)
 #define  CMD_MODE_DATA_WIDTH_16_BIT			(1 << 13)
@@ -7806,32 +7846,27 @@
 
 #define _MIPIA_HS_TX_TIMEOUT		(dev_priv->mipi_mmio_base + 0xb010)
 #define _MIPIC_HS_TX_TIMEOUT		(dev_priv->mipi_mmio_base + 0xb810)
-#define MIPI_HS_TX_TIMEOUT(port)	_MIPI_PORT(port, _MIPIA_HS_TX_TIMEOUT, \
-					_MIPIC_HS_TX_TIMEOUT)
+#define MIPI_HS_TX_TIMEOUT(port)	_MMIO_MIPI(port, _MIPIA_HS_TX_TIMEOUT, _MIPIC_HS_TX_TIMEOUT)
 #define  HIGH_SPEED_TX_TIMEOUT_COUNTER_MASK		0xffffff
 
 #define _MIPIA_LP_RX_TIMEOUT		(dev_priv->mipi_mmio_base + 0xb014)
 #define _MIPIC_LP_RX_TIMEOUT		(dev_priv->mipi_mmio_base + 0xb814)
-#define MIPI_LP_RX_TIMEOUT(port)	_MIPI_PORT(port, _MIPIA_LP_RX_TIMEOUT, \
-					_MIPIC_LP_RX_TIMEOUT)
+#define MIPI_LP_RX_TIMEOUT(port)	_MMIO_MIPI(port, _MIPIA_LP_RX_TIMEOUT, _MIPIC_LP_RX_TIMEOUT)
 #define  LOW_POWER_RX_TIMEOUT_COUNTER_MASK		0xffffff
 
 #define _MIPIA_TURN_AROUND_TIMEOUT	(dev_priv->mipi_mmio_base + 0xb018)
 #define _MIPIC_TURN_AROUND_TIMEOUT	(dev_priv->mipi_mmio_base + 0xb818)
-#define MIPI_TURN_AROUND_TIMEOUT(port)	_MIPI_PORT(port, \
-			_MIPIA_TURN_AROUND_TIMEOUT, _MIPIC_TURN_AROUND_TIMEOUT)
+#define MIPI_TURN_AROUND_TIMEOUT(port)	_MMIO_MIPI(port, _MIPIA_TURN_AROUND_TIMEOUT, _MIPIC_TURN_AROUND_TIMEOUT)
 #define  TURN_AROUND_TIMEOUT_MASK			0x3f
 
 #define _MIPIA_DEVICE_RESET_TIMER	(dev_priv->mipi_mmio_base + 0xb01c)
 #define _MIPIC_DEVICE_RESET_TIMER	(dev_priv->mipi_mmio_base + 0xb81c)
-#define MIPI_DEVICE_RESET_TIMER(port)	_MIPI_PORT(port, \
-			_MIPIA_DEVICE_RESET_TIMER, _MIPIC_DEVICE_RESET_TIMER)
+#define MIPI_DEVICE_RESET_TIMER(port)	_MMIO_MIPI(port, _MIPIA_DEVICE_RESET_TIMER, _MIPIC_DEVICE_RESET_TIMER)
 #define  DEVICE_RESET_TIMER_MASK			0xffff
 
 #define _MIPIA_DPI_RESOLUTION		(dev_priv->mipi_mmio_base + 0xb020)
 #define _MIPIC_DPI_RESOLUTION		(dev_priv->mipi_mmio_base + 0xb820)
-#define MIPI_DPI_RESOLUTION(port)	_MIPI_PORT(port, _MIPIA_DPI_RESOLUTION, \
-					_MIPIC_DPI_RESOLUTION)
+#define MIPI_DPI_RESOLUTION(port)	_MMIO_MIPI(port, _MIPIA_DPI_RESOLUTION, _MIPIC_DPI_RESOLUTION)
 #define  VERTICAL_ADDRESS_SHIFT				16
 #define  VERTICAL_ADDRESS_MASK				(0xffff << 16)
 #define  HORIZONTAL_ADDRESS_SHIFT			0
@@ -7839,8 +7874,7 @@
 
 #define _MIPIA_DBI_FIFO_THROTTLE	(dev_priv->mipi_mmio_base + 0xb024)
 #define _MIPIC_DBI_FIFO_THROTTLE	(dev_priv->mipi_mmio_base + 0xb824)
-#define MIPI_DBI_FIFO_THROTTLE(port)	_MIPI_PORT(port, \
-			_MIPIA_DBI_FIFO_THROTTLE, _MIPIC_DBI_FIFO_THROTTLE)
+#define MIPI_DBI_FIFO_THROTTLE(port)	_MMIO_MIPI(port, _MIPIA_DBI_FIFO_THROTTLE, _MIPIC_DBI_FIFO_THROTTLE)
 #define  DBI_FIFO_EMPTY_HALF				(0 << 0)
 #define  DBI_FIFO_EMPTY_QUARTER				(1 << 0)
 #define  DBI_FIFO_EMPTY_7_LOCATIONS			(2 << 0)
@@ -7848,50 +7882,41 @@
 /* regs below are bits 15:0 */
 #define _MIPIA_HSYNC_PADDING_COUNT	(dev_priv->mipi_mmio_base + 0xb028)
 #define _MIPIC_HSYNC_PADDING_COUNT	(dev_priv->mipi_mmio_base + 0xb828)
-#define MIPI_HSYNC_PADDING_COUNT(port)	_MIPI_PORT(port, \
-			_MIPIA_HSYNC_PADDING_COUNT, _MIPIC_HSYNC_PADDING_COUNT)
+#define MIPI_HSYNC_PADDING_COUNT(port)	_MMIO_MIPI(port, _MIPIA_HSYNC_PADDING_COUNT, _MIPIC_HSYNC_PADDING_COUNT)
 
 #define _MIPIA_HBP_COUNT		(dev_priv->mipi_mmio_base + 0xb02c)
 #define _MIPIC_HBP_COUNT		(dev_priv->mipi_mmio_base + 0xb82c)
-#define MIPI_HBP_COUNT(port)		_MIPI_PORT(port, _MIPIA_HBP_COUNT, \
-					_MIPIC_HBP_COUNT)
+#define MIPI_HBP_COUNT(port)		_MMIO_MIPI(port, _MIPIA_HBP_COUNT, _MIPIC_HBP_COUNT)
 
 #define _MIPIA_HFP_COUNT		(dev_priv->mipi_mmio_base + 0xb030)
 #define _MIPIC_HFP_COUNT		(dev_priv->mipi_mmio_base + 0xb830)
-#define MIPI_HFP_COUNT(port)		_MIPI_PORT(port, _MIPIA_HFP_COUNT, \
-					_MIPIC_HFP_COUNT)
+#define MIPI_HFP_COUNT(port)		_MMIO_MIPI(port, _MIPIA_HFP_COUNT, _MIPIC_HFP_COUNT)
 
 #define _MIPIA_HACTIVE_AREA_COUNT	(dev_priv->mipi_mmio_base + 0xb034)
 #define _MIPIC_HACTIVE_AREA_COUNT	(dev_priv->mipi_mmio_base + 0xb834)
-#define MIPI_HACTIVE_AREA_COUNT(port)	_MIPI_PORT(port, \
-			_MIPIA_HACTIVE_AREA_COUNT, _MIPIC_HACTIVE_AREA_COUNT)
+#define MIPI_HACTIVE_AREA_COUNT(port)	_MMIO_MIPI(port, _MIPIA_HACTIVE_AREA_COUNT, _MIPIC_HACTIVE_AREA_COUNT)
 
 #define _MIPIA_VSYNC_PADDING_COUNT	(dev_priv->mipi_mmio_base + 0xb038)
 #define _MIPIC_VSYNC_PADDING_COUNT	(dev_priv->mipi_mmio_base + 0xb838)
-#define MIPI_VSYNC_PADDING_COUNT(port)	_MIPI_PORT(port, \
-			_MIPIA_VSYNC_PADDING_COUNT, _MIPIC_VSYNC_PADDING_COUNT)
+#define MIPI_VSYNC_PADDING_COUNT(port)	_MMIO_MIPI(port, _MIPIA_VSYNC_PADDING_COUNT, _MIPIC_VSYNC_PADDING_COUNT)
 
 #define _MIPIA_VBP_COUNT		(dev_priv->mipi_mmio_base + 0xb03c)
 #define _MIPIC_VBP_COUNT		(dev_priv->mipi_mmio_base + 0xb83c)
-#define MIPI_VBP_COUNT(port)		_MIPI_PORT(port, _MIPIA_VBP_COUNT, \
-					_MIPIC_VBP_COUNT)
+#define MIPI_VBP_COUNT(port)		_MMIO_MIPI(port, _MIPIA_VBP_COUNT, _MIPIC_VBP_COUNT)
 
 #define _MIPIA_VFP_COUNT		(dev_priv->mipi_mmio_base + 0xb040)
 #define _MIPIC_VFP_COUNT		(dev_priv->mipi_mmio_base + 0xb840)
-#define MIPI_VFP_COUNT(port)		_MIPI_PORT(port, _MIPIA_VFP_COUNT, \
-					_MIPIC_VFP_COUNT)
+#define MIPI_VFP_COUNT(port)		_MMIO_MIPI(port, _MIPIA_VFP_COUNT, _MIPIC_VFP_COUNT)
 
 #define _MIPIA_HIGH_LOW_SWITCH_COUNT	(dev_priv->mipi_mmio_base + 0xb044)
 #define _MIPIC_HIGH_LOW_SWITCH_COUNT	(dev_priv->mipi_mmio_base + 0xb844)
-#define MIPI_HIGH_LOW_SWITCH_COUNT(port)	_MIPI_PORT(port,	\
-		_MIPIA_HIGH_LOW_SWITCH_COUNT, _MIPIC_HIGH_LOW_SWITCH_COUNT)
+#define MIPI_HIGH_LOW_SWITCH_COUNT(port)	_MMIO_MIPI(port,	_MIPIA_HIGH_LOW_SWITCH_COUNT, _MIPIC_HIGH_LOW_SWITCH_COUNT)
 
 /* regs above are bits 15:0 */
 
 #define _MIPIA_DPI_CONTROL		(dev_priv->mipi_mmio_base + 0xb048)
 #define _MIPIC_DPI_CONTROL		(dev_priv->mipi_mmio_base + 0xb848)
-#define MIPI_DPI_CONTROL(port)		_MIPI_PORT(port, _MIPIA_DPI_CONTROL, \
-					_MIPIC_DPI_CONTROL)
+#define MIPI_DPI_CONTROL(port)		_MMIO_MIPI(port, _MIPIA_DPI_CONTROL, _MIPIC_DPI_CONTROL)
 #define  DPI_LP_MODE					(1 << 6)
 #define  BACKLIGHT_OFF					(1 << 5)
 #define  BACKLIGHT_ON					(1 << 4)
@@ -7902,29 +7927,26 @@
 
 #define _MIPIA_DPI_DATA			(dev_priv->mipi_mmio_base + 0xb04c)
 #define _MIPIC_DPI_DATA			(dev_priv->mipi_mmio_base + 0xb84c)
-#define MIPI_DPI_DATA(port)		_MIPI_PORT(port, _MIPIA_DPI_DATA, \
-					_MIPIC_DPI_DATA)
+#define MIPI_DPI_DATA(port)		_MMIO_MIPI(port, _MIPIA_DPI_DATA, _MIPIC_DPI_DATA)
 #define  COMMAND_BYTE_SHIFT				0
 #define  COMMAND_BYTE_MASK				(0x3f << 0)
 
 #define _MIPIA_INIT_COUNT		(dev_priv->mipi_mmio_base + 0xb050)
 #define _MIPIC_INIT_COUNT		(dev_priv->mipi_mmio_base + 0xb850)
-#define MIPI_INIT_COUNT(port)		_MIPI_PORT(port, _MIPIA_INIT_COUNT, \
-					_MIPIC_INIT_COUNT)
+#define MIPI_INIT_COUNT(port)		_MMIO_MIPI(port, _MIPIA_INIT_COUNT, _MIPIC_INIT_COUNT)
 #define  MASTER_INIT_TIMER_SHIFT			0
 #define  MASTER_INIT_TIMER_MASK				(0xffff << 0)
 
 #define _MIPIA_MAX_RETURN_PKT_SIZE	(dev_priv->mipi_mmio_base + 0xb054)
 #define _MIPIC_MAX_RETURN_PKT_SIZE	(dev_priv->mipi_mmio_base + 0xb854)
-#define MIPI_MAX_RETURN_PKT_SIZE(port)	_MIPI_PORT(port, \
+#define MIPI_MAX_RETURN_PKT_SIZE(port)	_MMIO_MIPI(port, \
 			_MIPIA_MAX_RETURN_PKT_SIZE, _MIPIC_MAX_RETURN_PKT_SIZE)
 #define  MAX_RETURN_PKT_SIZE_SHIFT			0
 #define  MAX_RETURN_PKT_SIZE_MASK			(0x3ff << 0)
 
 #define _MIPIA_VIDEO_MODE_FORMAT	(dev_priv->mipi_mmio_base + 0xb058)
 #define _MIPIC_VIDEO_MODE_FORMAT	(dev_priv->mipi_mmio_base + 0xb858)
-#define MIPI_VIDEO_MODE_FORMAT(port)	_MIPI_PORT(port, \
-			_MIPIA_VIDEO_MODE_FORMAT, _MIPIC_VIDEO_MODE_FORMAT)
+#define MIPI_VIDEO_MODE_FORMAT(port)	_MMIO_MIPI(port, _MIPIA_VIDEO_MODE_FORMAT, _MIPIC_VIDEO_MODE_FORMAT)
 #define  RANDOM_DPI_DISPLAY_RESOLUTION			(1 << 4)
 #define  DISABLE_VIDEO_BTA				(1 << 3)
 #define  IP_TG_CONFIG					(1 << 2)
@@ -7934,8 +7956,7 @@
 
 #define _MIPIA_EOT_DISABLE		(dev_priv->mipi_mmio_base + 0xb05c)
 #define _MIPIC_EOT_DISABLE		(dev_priv->mipi_mmio_base + 0xb85c)
-#define MIPI_EOT_DISABLE(port)		_MIPI_PORT(port, _MIPIA_EOT_DISABLE, \
-					_MIPIC_EOT_DISABLE)
+#define MIPI_EOT_DISABLE(port)		_MMIO_MIPI(port, _MIPIA_EOT_DISABLE, _MIPIC_EOT_DISABLE)
 #define  LP_RX_TIMEOUT_ERROR_RECOVERY_DISABLE		(1 << 7)
 #define  HS_RX_TIMEOUT_ERROR_RECOVERY_DISABLE		(1 << 6)
 #define  LOW_CONTENTION_RECOVERY_DISABLE		(1 << 5)
@@ -7947,31 +7968,26 @@
 
 #define _MIPIA_LP_BYTECLK		(dev_priv->mipi_mmio_base + 0xb060)
 #define _MIPIC_LP_BYTECLK		(dev_priv->mipi_mmio_base + 0xb860)
-#define MIPI_LP_BYTECLK(port)		_MIPI_PORT(port, _MIPIA_LP_BYTECLK, \
-					_MIPIC_LP_BYTECLK)
+#define MIPI_LP_BYTECLK(port)		_MMIO_MIPI(port, _MIPIA_LP_BYTECLK, _MIPIC_LP_BYTECLK)
 #define  LP_BYTECLK_SHIFT				0
 #define  LP_BYTECLK_MASK				(0xffff << 0)
 
 /* bits 31:0 */
 #define _MIPIA_LP_GEN_DATA		(dev_priv->mipi_mmio_base + 0xb064)
 #define _MIPIC_LP_GEN_DATA		(dev_priv->mipi_mmio_base + 0xb864)
-#define MIPI_LP_GEN_DATA(port)		_MIPI_PORT(port, _MIPIA_LP_GEN_DATA, \
-					_MIPIC_LP_GEN_DATA)
+#define MIPI_LP_GEN_DATA(port)		_MMIO_MIPI(port, _MIPIA_LP_GEN_DATA, _MIPIC_LP_GEN_DATA)
 
 /* bits 31:0 */
 #define _MIPIA_HS_GEN_DATA		(dev_priv->mipi_mmio_base + 0xb068)
 #define _MIPIC_HS_GEN_DATA		(dev_priv->mipi_mmio_base + 0xb868)
-#define MIPI_HS_GEN_DATA(port)		_MIPI_PORT(port, _MIPIA_HS_GEN_DATA, \
-					_MIPIC_HS_GEN_DATA)
+#define MIPI_HS_GEN_DATA(port)		_MMIO_MIPI(port, _MIPIA_HS_GEN_DATA, _MIPIC_HS_GEN_DATA)
 
 #define _MIPIA_LP_GEN_CTRL		(dev_priv->mipi_mmio_base + 0xb06c)
 #define _MIPIC_LP_GEN_CTRL		(dev_priv->mipi_mmio_base + 0xb86c)
-#define MIPI_LP_GEN_CTRL(port)		_MIPI_PORT(port, _MIPIA_LP_GEN_CTRL, \
-					_MIPIC_LP_GEN_CTRL)
+#define MIPI_LP_GEN_CTRL(port)		_MMIO_MIPI(port, _MIPIA_LP_GEN_CTRL, _MIPIC_LP_GEN_CTRL)
 #define _MIPIA_HS_GEN_CTRL		(dev_priv->mipi_mmio_base + 0xb070)
 #define _MIPIC_HS_GEN_CTRL		(dev_priv->mipi_mmio_base + 0xb870)
-#define MIPI_HS_GEN_CTRL(port)		_MIPI_PORT(port, _MIPIA_HS_GEN_CTRL, \
-					_MIPIC_HS_GEN_CTRL)
+#define MIPI_HS_GEN_CTRL(port)		_MMIO_MIPI(port, _MIPIA_HS_GEN_CTRL, _MIPIC_HS_GEN_CTRL)
 #define  LONG_PACKET_WORD_COUNT_SHIFT			8
 #define  LONG_PACKET_WORD_COUNT_MASK			(0xffff << 8)
 #define  SHORT_PACKET_PARAM_SHIFT			8
@@ -7984,8 +8000,7 @@
 
 #define _MIPIA_GEN_FIFO_STAT		(dev_priv->mipi_mmio_base + 0xb074)
 #define _MIPIC_GEN_FIFO_STAT		(dev_priv->mipi_mmio_base + 0xb874)
-#define MIPI_GEN_FIFO_STAT(port)	_MIPI_PORT(port, _MIPIA_GEN_FIFO_STAT, \
-					_MIPIC_GEN_FIFO_STAT)
+#define MIPI_GEN_FIFO_STAT(port)	_MMIO_MIPI(port, _MIPIA_GEN_FIFO_STAT, _MIPIC_GEN_FIFO_STAT)
 #define  DPI_FIFO_EMPTY					(1 << 28)
 #define  DBI_FIFO_EMPTY					(1 << 27)
 #define  LP_CTRL_FIFO_EMPTY				(1 << 26)
@@ -8003,16 +8018,14 @@
 
 #define _MIPIA_HS_LS_DBI_ENABLE		(dev_priv->mipi_mmio_base + 0xb078)
 #define _MIPIC_HS_LS_DBI_ENABLE		(dev_priv->mipi_mmio_base + 0xb878)
-#define MIPI_HS_LP_DBI_ENABLE(port)	_MIPI_PORT(port, \
-			_MIPIA_HS_LS_DBI_ENABLE, _MIPIC_HS_LS_DBI_ENABLE)
+#define MIPI_HS_LP_DBI_ENABLE(port)	_MMIO_MIPI(port, _MIPIA_HS_LS_DBI_ENABLE, _MIPIC_HS_LS_DBI_ENABLE)
 #define  DBI_HS_LP_MODE_MASK				(1 << 0)
 #define  DBI_LP_MODE					(1 << 0)
 #define  DBI_HS_MODE					(0 << 0)
 
 #define _MIPIA_DPHY_PARAM		(dev_priv->mipi_mmio_base + 0xb080)
 #define _MIPIC_DPHY_PARAM		(dev_priv->mipi_mmio_base + 0xb880)
-#define MIPI_DPHY_PARAM(port)		_MIPI_PORT(port, _MIPIA_DPHY_PARAM, \
-					_MIPIC_DPHY_PARAM)
+#define MIPI_DPHY_PARAM(port)		_MMIO_MIPI(port, _MIPIA_DPHY_PARAM, _MIPIC_DPHY_PARAM)
 #define  EXIT_ZERO_COUNT_SHIFT				24
 #define  EXIT_ZERO_COUNT_MASK				(0x3f << 24)
 #define  TRAIL_COUNT_SHIFT				16
@@ -8025,15 +8038,11 @@
 /* bits 31:0 */
 #define _MIPIA_DBI_BW_CTRL		(dev_priv->mipi_mmio_base + 0xb084)
 #define _MIPIC_DBI_BW_CTRL		(dev_priv->mipi_mmio_base + 0xb884)
-#define MIPI_DBI_BW_CTRL(port)		_MIPI_PORT(port, _MIPIA_DBI_BW_CTRL, \
-					_MIPIC_DBI_BW_CTRL)
+#define MIPI_DBI_BW_CTRL(port)		_MMIO_MIPI(port, _MIPIA_DBI_BW_CTRL, _MIPIC_DBI_BW_CTRL)
 
-#define _MIPIA_CLK_LANE_SWITCH_TIME_CNT		(dev_priv->mipi_mmio_base \
-							+ 0xb088)
-#define _MIPIC_CLK_LANE_SWITCH_TIME_CNT		(dev_priv->mipi_mmio_base \
-							+ 0xb888)
-#define MIPI_CLK_LANE_SWITCH_TIME_CNT(port)	_MIPI_PORT(port, \
-	_MIPIA_CLK_LANE_SWITCH_TIME_CNT, _MIPIC_CLK_LANE_SWITCH_TIME_CNT)
+#define _MIPIA_CLK_LANE_SWITCH_TIME_CNT		(dev_priv->mipi_mmio_base + 0xb088)
+#define _MIPIC_CLK_LANE_SWITCH_TIME_CNT		(dev_priv->mipi_mmio_base + 0xb888)
+#define MIPI_CLK_LANE_SWITCH_TIME_CNT(port)	_MMIO_MIPI(port, _MIPIA_CLK_LANE_SWITCH_TIME_CNT, _MIPIC_CLK_LANE_SWITCH_TIME_CNT)
 #define  LP_HS_SSW_CNT_SHIFT				16
 #define  LP_HS_SSW_CNT_MASK				(0xffff << 16)
 #define  HS_LP_PWR_SW_CNT_SHIFT				0
@@ -8041,19 +8050,16 @@
 
 #define _MIPIA_STOP_STATE_STALL		(dev_priv->mipi_mmio_base + 0xb08c)
 #define _MIPIC_STOP_STATE_STALL		(dev_priv->mipi_mmio_base + 0xb88c)
-#define MIPI_STOP_STATE_STALL(port)	_MIPI_PORT(port, \
-			_MIPIA_STOP_STATE_STALL, _MIPIC_STOP_STATE_STALL)
+#define MIPI_STOP_STATE_STALL(port)	_MMIO_MIPI(port, _MIPIA_STOP_STATE_STALL, _MIPIC_STOP_STATE_STALL)
 #define  STOP_STATE_STALL_COUNTER_SHIFT			0
 #define  STOP_STATE_STALL_COUNTER_MASK			(0xff << 0)
 
 #define _MIPIA_INTR_STAT_REG_1		(dev_priv->mipi_mmio_base + 0xb090)
 #define _MIPIC_INTR_STAT_REG_1		(dev_priv->mipi_mmio_base + 0xb890)
-#define MIPI_INTR_STAT_REG_1(port)	_MIPI_PORT(port, \
-				_MIPIA_INTR_STAT_REG_1, _MIPIC_INTR_STAT_REG_1)
+#define MIPI_INTR_STAT_REG_1(port)	_MMIO_MIPI(port, _MIPIA_INTR_STAT_REG_1, _MIPIC_INTR_STAT_REG_1)
 #define _MIPIA_INTR_EN_REG_1		(dev_priv->mipi_mmio_base + 0xb094)
 #define _MIPIC_INTR_EN_REG_1		(dev_priv->mipi_mmio_base + 0xb894)
-#define MIPI_INTR_EN_REG_1(port)	_MIPI_PORT(port, _MIPIA_INTR_EN_REG_1, \
-					_MIPIC_INTR_EN_REG_1)
+#define MIPI_INTR_EN_REG_1(port)	_MMIO_MIPI(port, _MIPIA_INTR_EN_REG_1, _MIPIC_INTR_EN_REG_1)
 #define  RX_CONTENTION_DETECTED				(1 << 0)
 
 /* XXX: only pipe A ?!? */
@@ -8073,8 +8079,7 @@
 
 #define _MIPIA_CTRL			(dev_priv->mipi_mmio_base + 0xb104)
 #define _MIPIC_CTRL			(dev_priv->mipi_mmio_base + 0xb904)
-#define MIPI_CTRL(port)			_MIPI_PORT(port, _MIPIA_CTRL, \
-					_MIPIC_CTRL)
+#define MIPI_CTRL(port)			_MMIO_MIPI(port, _MIPIA_CTRL, _MIPIC_CTRL)
 #define  ESCAPE_CLOCK_DIVIDER_SHIFT			5 /* A only */
 #define  ESCAPE_CLOCK_DIVIDER_MASK			(3 << 5)
 #define  ESCAPE_CLOCK_DIVIDER_1				(0 << 5)
@@ -8093,23 +8098,20 @@
 
 #define _MIPIA_DATA_ADDRESS		(dev_priv->mipi_mmio_base + 0xb108)
 #define _MIPIC_DATA_ADDRESS		(dev_priv->mipi_mmio_base + 0xb908)
-#define MIPI_DATA_ADDRESS(port)		_MIPI_PORT(port, _MIPIA_DATA_ADDRESS, \
-					_MIPIC_DATA_ADDRESS)
+#define MIPI_DATA_ADDRESS(port)		_MMIO_MIPI(port, _MIPIA_DATA_ADDRESS, _MIPIC_DATA_ADDRESS)
 #define  DATA_MEM_ADDRESS_SHIFT				5
 #define  DATA_MEM_ADDRESS_MASK				(0x7ffffff << 5)
 #define  DATA_VALID					(1 << 0)
 
 #define _MIPIA_DATA_LENGTH		(dev_priv->mipi_mmio_base + 0xb10c)
 #define _MIPIC_DATA_LENGTH		(dev_priv->mipi_mmio_base + 0xb90c)
-#define MIPI_DATA_LENGTH(port)		_MIPI_PORT(port, _MIPIA_DATA_LENGTH, \
-					_MIPIC_DATA_LENGTH)
+#define MIPI_DATA_LENGTH(port)		_MMIO_MIPI(port, _MIPIA_DATA_LENGTH, _MIPIC_DATA_LENGTH)
 #define  DATA_LENGTH_SHIFT				0
 #define  DATA_LENGTH_MASK				(0xfffff << 0)
 
 #define _MIPIA_COMMAND_ADDRESS		(dev_priv->mipi_mmio_base + 0xb110)
 #define _MIPIC_COMMAND_ADDRESS		(dev_priv->mipi_mmio_base + 0xb910)
-#define MIPI_COMMAND_ADDRESS(port)	_MIPI_PORT(port, \
-				_MIPIA_COMMAND_ADDRESS, _MIPIC_COMMAND_ADDRESS)
+#define MIPI_COMMAND_ADDRESS(port)	_MMIO_MIPI(port, _MIPIA_COMMAND_ADDRESS, _MIPIC_COMMAND_ADDRESS)
 #define  COMMAND_MEM_ADDRESS_SHIFT			5
 #define  COMMAND_MEM_ADDRESS_MASK			(0x7ffffff << 5)
 #define  AUTO_PWG_ENABLE				(1 << 2)
@@ -8118,21 +8120,17 @@
 
 #define _MIPIA_COMMAND_LENGTH		(dev_priv->mipi_mmio_base + 0xb114)
 #define _MIPIC_COMMAND_LENGTH		(dev_priv->mipi_mmio_base + 0xb914)
-#define MIPI_COMMAND_LENGTH(port)	_MIPI_PORT(port, _MIPIA_COMMAND_LENGTH, \
-					_MIPIC_COMMAND_LENGTH)
+#define MIPI_COMMAND_LENGTH(port)	_MMIO_MIPI(port, _MIPIA_COMMAND_LENGTH, _MIPIC_COMMAND_LENGTH)
 #define  COMMAND_LENGTH_SHIFT(n)			(8 * (n)) /* n: 0...3 */
 #define  COMMAND_LENGTH_MASK(n)				(0xff << (8 * (n)))
 
 #define _MIPIA_READ_DATA_RETURN0	(dev_priv->mipi_mmio_base + 0xb118)
 #define _MIPIC_READ_DATA_RETURN0	(dev_priv->mipi_mmio_base + 0xb918)
-#define MIPI_READ_DATA_RETURN(port, n) \
-	(_MIPI_PORT(port, _MIPIA_READ_DATA_RETURN0, _MIPIC_READ_DATA_RETURN0) \
-					+ 4 * (n)) /* n: 0...7 */
+#define MIPI_READ_DATA_RETURN(port, n) _MMIO(_MIPI(port, _MIPIA_READ_DATA_RETURN0, _MIPIC_READ_DATA_RETURN0) + 4 * (n)) /* n: 0...7 */
 
 #define _MIPIA_READ_DATA_VALID		(dev_priv->mipi_mmio_base + 0xb138)
 #define _MIPIC_READ_DATA_VALID		(dev_priv->mipi_mmio_base + 0xb938)
-#define MIPI_READ_DATA_VALID(port)	_MIPI_PORT(port, \
-				_MIPIA_READ_DATA_VALID, _MIPIC_READ_DATA_VALID)
+#define MIPI_READ_DATA_VALID(port)	_MMIO_MIPI(port, _MIPIA_READ_DATA_VALID, _MIPIC_READ_DATA_VALID)
 #define  READ_DATA_VALID(n)				(1 << (n))
 
 /* For UMS only (deprecated): */
@@ -8140,12 +8138,12 @@
 #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
 
 /* MOCS (Memory Object Control State) registers */
-#define GEN9_LNCFCMOCS0		0xb020	/* L3 Cache Control base */
+#define GEN9_LNCFCMOCS(i)	_MMIO(0xb020 + (i) * 4)	/* L3 Cache Control */
 
-#define GEN9_GFX_MOCS_0		0xc800	/* Graphics MOCS base register*/
-#define GEN9_MFX0_MOCS_0	0xc900	/* Media 0 MOCS base register*/
-#define GEN9_MFX1_MOCS_0	0xca00	/* Media 1 MOCS base register*/
-#define GEN9_VEBOX_MOCS_0	0xcb00	/* Video MOCS base register*/
-#define GEN9_BLT_MOCS_0		0xcc00	/* Blitter MOCS base register*/
+#define GEN9_GFX_MOCS(i)	_MMIO(0xc800 + (i) * 4)	/* Graphics MOCS registers */
+#define GEN9_MFX0_MOCS(i)	_MMIO(0xc900 + (i) * 4)	/* Media 0 MOCS registers */
+#define GEN9_MFX1_MOCS(i)	_MMIO(0xca00 + (i) * 4)	/* Media 1 MOCS registers */
+#define GEN9_VEBOX_MOCS(i)	_MMIO(0xcb00 + (i) * 4)	/* Video MOCS registers */
+#define GEN9_BLT_MOCS(i)	_MMIO(0xcc00 + (i) * 4)	/* Blitter MOCS registers */
 
 #endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 50ce9ce..f929c61 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -35,7 +35,8 @@
 #define dev_to_drm_minor(d) dev_get_drvdata((d))
 
 #ifdef CONFIG_PM
-static u32 calc_residency(struct drm_device *dev, const u32 reg)
+static u32 calc_residency(struct drm_device *dev,
+			  i915_reg_t reg)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u64 raw_time; /* 32b value may overflow during fixed point math */
diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
index 04fe849..52b2d40 100644
--- a/drivers/gpu/drm/i915/i915_trace.h
+++ b/drivers/gpu/drm/i915/i915_trace.h
@@ -664,7 +664,7 @@
 );
 
 TRACE_EVENT_CONDITION(i915_reg_rw,
-	TP_PROTO(bool write, u32 reg, u64 val, int len, bool trace),
+	TP_PROTO(bool write, i915_reg_t reg, u64 val, int len, bool trace),
 
 	TP_ARGS(write, reg, val, len, trace),
 
@@ -679,7 +679,7 @@
 
 	TP_fast_assign(
 		__entry->val = (u64)val;
-		__entry->reg = reg;
+		__entry->reg = i915_mmio_reg_offset(reg);
 		__entry->write = write;
 		__entry->len = len;
 		),
diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c
index 5eee75b..dea7429 100644
--- a/drivers/gpu/drm/i915/i915_vgpu.c
+++ b/drivers/gpu/drm/i915/i915_vgpu.c
@@ -69,13 +69,13 @@
 	if (!IS_HASWELL(dev))
 		return;
 
-	magic = readq(dev_priv->regs + vgtif_reg(magic));
+	magic = __raw_i915_read64(dev_priv, vgtif_reg(magic));
 	if (magic != VGT_MAGIC)
 		return;
 
 	version = INTEL_VGT_IF_VERSION_ENCODE(
-		readw(dev_priv->regs + vgtif_reg(version_major)),
-		readw(dev_priv->regs + vgtif_reg(version_minor)));
+		__raw_i915_read16(dev_priv, vgtif_reg(version_major)),
+		__raw_i915_read16(dev_priv, vgtif_reg(version_minor)));
 	if (version != INTEL_VGT_IF_VERSION) {
 		DRM_INFO("VGT interface version mismatch!\n");
 		return;
diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
index 21c97f4..3c83b47 100644
--- a/drivers/gpu/drm/i915/i915_vgpu.h
+++ b/drivers/gpu/drm/i915/i915_vgpu.h
@@ -92,14 +92,10 @@
 	uint32_t g2v_notify;
 	uint32_t rsv6[7];
 
-	uint32_t pdp0_lo;
-	uint32_t pdp0_hi;
-	uint32_t pdp1_lo;
-	uint32_t pdp1_hi;
-	uint32_t pdp2_lo;
-	uint32_t pdp2_hi;
-	uint32_t pdp3_lo;
-	uint32_t pdp3_hi;
+	struct {
+		uint32_t lo;
+		uint32_t hi;
+	} pdp[4];
 
 	uint32_t execlist_context_descriptor_lo;
 	uint32_t execlist_context_descriptor_hi;
@@ -108,7 +104,7 @@
 } __packed;
 
 #define vgtif_reg(x) \
-	(VGT_PVINFO_PAGE + (long)&((struct vgt_if *)NULL)->x)
+	_MMIO((VGT_PVINFO_PAGE + (long)&((struct vgt_if *)NULL)->x))
 
 /* vGPU display status to be used by the host side */
 #define VGT_DRV_DISPLAY_NOT_READY 0
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index f1975f2..643f342 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -94,6 +94,7 @@
 	__drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base);
 
 	crtc_state->update_pipe = false;
+	crtc_state->disable_lp_wm = false;
 
 	return &crtc_state->base;
 }
@@ -205,8 +206,6 @@
 				 * but since this plane is unchanged just do the
 				 * minimum required validation.
 				 */
-				if (plane->type == DRM_PLANE_TYPE_PRIMARY)
-					intel_crtc->atomic.wait_for_flips = true;
 				crtc_state->base.planes_changed = true;
 			}
 
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
index a119806..c6bb0fc 100644
--- a/drivers/gpu/drm/i915/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -84,6 +84,7 @@
 	state = &intel_state->base;
 
 	__drm_atomic_helper_plane_duplicate_state(plane, state);
+	intel_state->wait_req = NULL;
 
 	return state;
 }
@@ -100,6 +101,7 @@
 intel_plane_destroy_state(struct drm_plane *plane,
 			  struct drm_plane_state *state)
 {
+	WARN_ON(state && to_intel_plane_state(state)->wait_req);
 	drm_atomic_helper_plane_destroy_state(plane, state);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index 4dccd9b..de465f2 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -161,9 +161,9 @@
 }
 
 static bool intel_eld_uptodate(struct drm_connector *connector,
-			       int reg_eldv, uint32_t bits_eldv,
-			       int reg_elda, uint32_t bits_elda,
-			       int reg_edid)
+			       i915_reg_t reg_eldv, uint32_t bits_eldv,
+			       i915_reg_t reg_elda, uint32_t bits_elda,
+			       i915_reg_t reg_edid)
 {
 	struct drm_i915_private *dev_priv = connector->dev->dev_private;
 	uint8_t *eld = connector->eld;
@@ -364,8 +364,7 @@
 	enum port port = intel_dig_port->port;
 	enum pipe pipe = intel_crtc->pipe;
 	uint32_t tmp, eldv;
-	int aud_config;
-	int aud_cntrl_st2;
+	i915_reg_t aud_config, aud_cntrl_st2;
 
 	DRM_DEBUG_KMS("Disable audio codec on port %c, pipe %c\n",
 		      port_name(port), pipe_name(pipe));
@@ -416,10 +415,7 @@
 	uint32_t eldv;
 	uint32_t tmp;
 	int len, i;
-	int hdmiw_hdmiedid;
-	int aud_config;
-	int aud_cntl_st;
-	int aud_cntrl_st2;
+	i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2;
 
 	DRM_DEBUG_KMS("Enable audio codec on port %c, pipe %c, %u bytes ELD\n",
 		      port_name(port), pipe_name(pipe), drm_eld_size(eld));
@@ -525,6 +521,10 @@
 		dev_priv->display.audio_codec_enable(connector, intel_encoder,
 						     adjusted_mode);
 
+	mutex_lock(&dev_priv->av_mutex);
+	intel_dig_port->audio_connector = connector;
+	mutex_unlock(&dev_priv->av_mutex);
+
 	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
 		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port);
 }
@@ -548,6 +548,10 @@
 	if (dev_priv->display.audio_codec_disable)
 		dev_priv->display.audio_codec_disable(intel_encoder);
 
+	mutex_lock(&dev_priv->av_mutex);
+	intel_dig_port->audio_connector = NULL;
+	mutex_unlock(&dev_priv->av_mutex);
+
 	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
 		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port);
 }
@@ -591,7 +595,7 @@
 	struct drm_i915_private *dev_priv = dev_to_i915(dev);
 	u32 tmp;
 
-	if (!IS_SKYLAKE(dev_priv))
+	if (!IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv))
 		return;
 
 	/*
@@ -632,44 +636,40 @@
 						int port, int rate)
 {
 	struct drm_i915_private *dev_priv = dev_to_i915(dev);
-	struct drm_device *drm_dev = dev_priv->dev;
 	struct intel_encoder *intel_encoder;
-	struct intel_digital_port *intel_dig_port;
 	struct intel_crtc *crtc;
 	struct drm_display_mode *mode;
 	struct i915_audio_component *acomp = dev_priv->audio_component;
-	enum pipe pipe = -1;
+	enum pipe pipe = INVALID_PIPE;
 	u32 tmp;
 	int n;
+	int err = 0;
 
-	/* HSW, BDW SKL need this fix */
+	/* HSW, BDW, SKL, KBL need this fix */
 	if (!IS_SKYLAKE(dev_priv) &&
-		!IS_BROADWELL(dev_priv) &&
-		!IS_HASWELL(dev_priv))
+	    !IS_KABYLAKE(dev_priv) &&
+	    !IS_BROADWELL(dev_priv) &&
+	    !IS_HASWELL(dev_priv))
 		return 0;
 
 	mutex_lock(&dev_priv->av_mutex);
 	/* 1. get the pipe */
-	for_each_intel_encoder(drm_dev, intel_encoder) {
-		if (intel_encoder->type != INTEL_OUTPUT_HDMI)
-			continue;
-		intel_dig_port = enc_to_dig_port(&intel_encoder->base);
-		if (port == intel_dig_port->port) {
-			crtc = to_intel_crtc(intel_encoder->base.crtc);
-			if (!crtc) {
-				DRM_DEBUG_KMS("%s: crtc is NULL\n", __func__);
-				continue;
-			}
-			pipe = crtc->pipe;
-			break;
-		}
+	intel_encoder = dev_priv->dig_port_map[port];
+	/* intel_encoder might be NULL for DP MST */
+	if (!intel_encoder || !intel_encoder->base.crtc ||
+	    intel_encoder->type != INTEL_OUTPUT_HDMI) {
+		DRM_DEBUG_KMS("no valid port %c\n", port_name(port));
+		err = -ENODEV;
+		goto unlock;
 	}
-
+	crtc = to_intel_crtc(intel_encoder->base.crtc);
+	pipe = crtc->pipe;
 	if (pipe == INVALID_PIPE) {
 		DRM_DEBUG_KMS("no pipe for the port %c\n", port_name(port));
-		mutex_unlock(&dev_priv->av_mutex);
-		return -ENODEV;
+		err = -ENODEV;
+		goto unlock;
 	}
+
 	DRM_DEBUG_KMS("pipe %c connects port %c\n",
 				  pipe_name(pipe), port_name(port));
 	mode = &crtc->config->base.adjusted_mode;
@@ -682,8 +682,7 @@
 		tmp = I915_READ(HSW_AUD_CFG(pipe));
 		tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
 		I915_WRITE(HSW_AUD_CFG(pipe), tmp);
-		mutex_unlock(&dev_priv->av_mutex);
-		return 0;
+		goto unlock;
 	}
 
 	n = audio_config_get_n(mode, rate);
@@ -693,8 +692,7 @@
 		tmp = I915_READ(HSW_AUD_CFG(pipe));
 		tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
 		I915_WRITE(HSW_AUD_CFG(pipe), tmp);
-		mutex_unlock(&dev_priv->av_mutex);
-		return 0;
+		goto unlock;
 	}
 
 	/* 3. set the N/CTS/M */
@@ -702,8 +700,37 @@
 	tmp = audio_config_setup_n_reg(n, tmp);
 	I915_WRITE(HSW_AUD_CFG(pipe), tmp);
 
+ unlock:
 	mutex_unlock(&dev_priv->av_mutex);
-	return 0;
+	return err;
+}
+
+static int i915_audio_component_get_eld(struct device *dev, int port,
+					bool *enabled,
+					unsigned char *buf, int max_bytes)
+{
+	struct drm_i915_private *dev_priv = dev_to_i915(dev);
+	struct intel_encoder *intel_encoder;
+	struct intel_digital_port *intel_dig_port;
+	const u8 *eld;
+	int ret = -EINVAL;
+
+	mutex_lock(&dev_priv->av_mutex);
+	intel_encoder = dev_priv->dig_port_map[port];
+	/* intel_encoder might be NULL for DP MST */
+	if (intel_encoder) {
+		ret = 0;
+		intel_dig_port = enc_to_dig_port(&intel_encoder->base);
+		*enabled = intel_dig_port->audio_connector != NULL;
+		if (*enabled) {
+			eld = intel_dig_port->audio_connector->eld;
+			ret = drm_eld_size(eld);
+			memcpy(buf, eld, min(max_bytes, ret));
+		}
+	}
+
+	mutex_unlock(&dev_priv->av_mutex);
+	return ret;
 }
 
 static const struct i915_audio_component_ops i915_audio_component_ops = {
@@ -713,6 +740,7 @@
 	.codec_wake_override = i915_audio_component_codec_wake_override,
 	.get_cdclk_freq	= i915_audio_component_get_cdclk_freq,
 	.sync_audio_rate = i915_audio_component_sync_audio_rate,
+	.get_eld	= i915_audio_component_get_eld,
 };
 
 static int i915_audio_component_bind(struct device *i915_dev,
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 6a2c76e..27b3e61 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -50,7 +50,7 @@
 	 * encoder's enable/disable callbacks */
 	struct intel_connector *connector;
 	bool force_hotplug_required;
-	u32 adpa_reg;
+	i915_reg_t adpa_reg;
 };
 
 static struct intel_crt *intel_encoder_to_crt(struct intel_encoder *encoder)
@@ -480,12 +480,8 @@
 	uint32_t vsample;
 	uint32_t vblank, vblank_start, vblank_end;
 	uint32_t dsl;
-	uint32_t bclrpat_reg;
-	uint32_t vtotal_reg;
-	uint32_t vblank_reg;
-	uint32_t vsync_reg;
-	uint32_t pipeconf_reg;
-	uint32_t pipe_dsl_reg;
+	i915_reg_t bclrpat_reg, vtotal_reg,
+		vblank_reg, vsync_reg, pipeconf_reg, pipe_dsl_reg;
 	uint8_t	st00;
 	enum drm_connector_status status;
 
@@ -518,7 +514,7 @@
 		/* Wait for next Vblank to substitue
 		 * border color for Color info */
 		intel_wait_for_vblank(dev, pipe);
-		st00 = I915_READ8(VGA_MSR_WRITE);
+		st00 = I915_READ8(_VGA_MSR_WRITE);
 		status = ((st00 & (1 << 4)) != 0) ?
 			connector_status_connected :
 			connector_status_disconnected;
@@ -563,7 +559,7 @@
 		do {
 			count++;
 			/* Read the ST00 VGA status register */
-			st00 = I915_READ8(VGA_MSR_WRITE);
+			st00 = I915_READ8(_VGA_MSR_WRITE);
 			if (st00 & (1 << 4))
 				detect++;
 		} while ((I915_READ(pipe_dsl_reg) == dsl));
diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c
index 9e530a7..6c6a669 100644
--- a/drivers/gpu/drm/i915/intel_csr.c
+++ b/drivers/gpu/drm/i915/intel_csr.c
@@ -47,21 +47,10 @@
 MODULE_FIRMWARE(I915_CSR_SKL);
 MODULE_FIRMWARE(I915_CSR_BXT);
 
-/*
-* SKL CSR registers for DC5 and DC6
-*/
-#define CSR_PROGRAM(i)			(0x80000 + (i) * 4)
-#define CSR_SSP_BASE_ADDR_GEN9		0x00002FC0
-#define CSR_HTP_ADDR_SKL		0x00500034
-#define CSR_SSP_BASE			0x8F074
-#define CSR_HTP_SKL			0x8F004
-#define CSR_LAST_WRITE			0x8F034
-#define CSR_LAST_WRITE_VALUE		0xc003b400
-/* MMIO address range for CSR program (0x80000 - 0x82FFF) */
+#define SKL_CSR_VERSION_REQUIRED	CSR_VERSION(1, 23)
+
 #define CSR_MAX_FW_SIZE			0x2FFF
 #define CSR_DEFAULT_FW_OFFSET		0xFFFFFFFF
-#define CSR_MMIO_START_RANGE	0x80000
-#define CSR_MMIO_END_RANGE		0x8FFFF
 
 struct intel_css_header {
 	/* 0x09 for DMC */
@@ -178,166 +167,134 @@
 };
 
 static const struct stepping_info skl_stepping_info[] = {
-		{'A', '0'}, {'B', '0'}, {'C', '0'},
-		{'D', '0'}, {'E', '0'}, {'F', '0'},
-		{'G', '0'}, {'H', '0'}, {'I', '0'}
+	{'A', '0'}, {'B', '0'}, {'C', '0'},
+	{'D', '0'}, {'E', '0'}, {'F', '0'},
+	{'G', '0'}, {'H', '0'}, {'I', '0'}
 };
 
-static struct stepping_info bxt_stepping_info[] = {
+static const struct stepping_info bxt_stepping_info[] = {
 	{'A', '0'}, {'A', '1'}, {'A', '2'},
 	{'B', '0'}, {'B', '1'}, {'B', '2'}
 };
 
-static char intel_get_stepping(struct drm_device *dev)
+static const struct stepping_info *intel_get_stepping_info(struct drm_device *dev)
 {
-	if (IS_SKYLAKE(dev) && (dev->pdev->revision <
-			ARRAY_SIZE(skl_stepping_info)))
-		return skl_stepping_info[dev->pdev->revision].stepping;
-	else if (IS_BROXTON(dev) && (dev->pdev->revision <
-				ARRAY_SIZE(bxt_stepping_info)))
-		return bxt_stepping_info[dev->pdev->revision].stepping;
-	else
-		return -ENODATA;
-}
+	const struct stepping_info *si;
+	unsigned int size;
 
-static char intel_get_substepping(struct drm_device *dev)
-{
-	if (IS_SKYLAKE(dev) && (dev->pdev->revision <
-			ARRAY_SIZE(skl_stepping_info)))
-		return skl_stepping_info[dev->pdev->revision].substepping;
-	else if (IS_BROXTON(dev) && (dev->pdev->revision <
-			ARRAY_SIZE(bxt_stepping_info)))
-		return bxt_stepping_info[dev->pdev->revision].substepping;
-	else
-		return -ENODATA;
-}
+	if (IS_SKYLAKE(dev)) {
+		size = ARRAY_SIZE(skl_stepping_info);
+		si = skl_stepping_info;
+	} else if (IS_BROXTON(dev)) {
+		size = ARRAY_SIZE(bxt_stepping_info);
+		si = bxt_stepping_info;
+	} else {
+		return NULL;
+	}
 
-/**
- * intel_csr_load_status_get() - to get firmware loading status.
- * @dev_priv: i915 device.
- *
- * This function helps to get the firmware loading status.
- *
- * Return: Firmware loading status.
- */
-enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv)
-{
-	enum csr_state state;
+	if (INTEL_REVID(dev) < size)
+		return si + INTEL_REVID(dev);
 
-	mutex_lock(&dev_priv->csr_lock);
-	state = dev_priv->csr.state;
-	mutex_unlock(&dev_priv->csr_lock);
-
-	return state;
-}
-
-/**
- * intel_csr_load_status_set() - help to set firmware loading status.
- * @dev_priv: i915 device.
- * @state: enumeration of firmware loading status.
- *
- * Set the firmware loading status.
- */
-void intel_csr_load_status_set(struct drm_i915_private *dev_priv,
-			enum csr_state state)
-{
-	mutex_lock(&dev_priv->csr_lock);
-	dev_priv->csr.state = state;
-	mutex_unlock(&dev_priv->csr_lock);
+	return NULL;
 }
 
 /**
  * intel_csr_load_program() - write the firmware from memory to register.
- * @dev: drm device.
+ * @dev_priv: i915 drm device.
  *
  * CSR firmware is read from a .bin file and kept in internal memory one time.
  * Everytime display comes back from low power state this function is called to
  * copy the firmware from internal memory to registers.
  */
-void intel_csr_load_program(struct drm_device *dev)
+void intel_csr_load_program(struct drm_i915_private *dev_priv)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 *payload = dev_priv->csr.dmc_payload;
 	uint32_t i, fw_size;
 
-	if (!IS_GEN9(dev)) {
+	if (!IS_GEN9(dev_priv)) {
 		DRM_ERROR("No CSR support available for this platform\n");
 		return;
 	}
 
-	/*
-	 * FIXME: Firmware gets lost on S3/S4, but not when entering system
-	 * standby or suspend-to-idle (which is just like forced runtime pm).
-	 * Unfortunately the ACPI subsystem doesn't yet give us a way to
-	 * differentiate this, hence figure it out with this hack.
-	 */
-	if (I915_READ(CSR_PROGRAM(0)))
+	if (!dev_priv->csr.dmc_payload) {
+		DRM_ERROR("Tried to program CSR with empty payload\n");
 		return;
+	}
 
-	mutex_lock(&dev_priv->csr_lock);
 	fw_size = dev_priv->csr.dmc_fw_size;
 	for (i = 0; i < fw_size; i++)
 		I915_WRITE(CSR_PROGRAM(i), payload[i]);
 
 	for (i = 0; i < dev_priv->csr.mmio_count; i++) {
 		I915_WRITE(dev_priv->csr.mmioaddr[i],
-			dev_priv->csr.mmiodata[i]);
+			   dev_priv->csr.mmiodata[i]);
 	}
-
-	dev_priv->csr.state = FW_LOADED;
-	mutex_unlock(&dev_priv->csr_lock);
 }
 
-static void finish_csr_load(const struct firmware *fw, void *context)
+static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv,
+			      const struct firmware *fw)
 {
-	struct drm_i915_private *dev_priv = context;
 	struct drm_device *dev = dev_priv->dev;
 	struct intel_css_header *css_header;
 	struct intel_package_header *package_header;
 	struct intel_dmc_header *dmc_header;
 	struct intel_csr *csr = &dev_priv->csr;
-	char stepping = intel_get_stepping(dev);
-	char substepping = intel_get_substepping(dev);
+	const struct stepping_info *stepping_info = intel_get_stepping_info(dev);
+	char stepping, substepping;
 	uint32_t dmc_offset = CSR_DEFAULT_FW_OFFSET, readcount = 0, nbytes;
 	uint32_t i;
 	uint32_t *dmc_payload;
-	bool fw_loaded = false;
 
-	if (!fw) {
-		i915_firmware_load_error_print(csr->fw_path, 0);
-		goto out;
-	}
+	if (!fw)
+		return NULL;
 
-	if ((stepping == -ENODATA) || (substepping == -ENODATA)) {
+	if (!stepping_info) {
 		DRM_ERROR("Unknown stepping info, firmware loading failed\n");
-		goto out;
+		return NULL;
 	}
 
+	stepping = stepping_info->stepping;
+	substepping = stepping_info->substepping;
+
 	/* Extract CSS Header information*/
 	css_header = (struct intel_css_header *)fw->data;
 	if (sizeof(struct intel_css_header) !=
-		(css_header->header_len * 4)) {
+	    (css_header->header_len * 4)) {
 		DRM_ERROR("Firmware has wrong CSS header length %u bytes\n",
-			(css_header->header_len * 4));
-		goto out;
+			  (css_header->header_len * 4));
+		return NULL;
 	}
+
+	csr->version = css_header->version;
+
+	if (IS_SKYLAKE(dev) && csr->version < SKL_CSR_VERSION_REQUIRED) {
+		DRM_INFO("Refusing to load old Skylake DMC firmware v%u.%u,"
+			 " please upgrade to v%u.%u or later"
+			 " [https://01.org/linuxgraphics/intel-linux-graphics-firmwares].\n",
+			 CSR_VERSION_MAJOR(csr->version),
+			 CSR_VERSION_MINOR(csr->version),
+			 CSR_VERSION_MAJOR(SKL_CSR_VERSION_REQUIRED),
+			 CSR_VERSION_MINOR(SKL_CSR_VERSION_REQUIRED));
+		return NULL;
+	}
+
 	readcount += sizeof(struct intel_css_header);
 
 	/* Extract Package Header information*/
 	package_header = (struct intel_package_header *)
-					&fw->data[readcount];
+		&fw->data[readcount];
 	if (sizeof(struct intel_package_header) !=
-		(package_header->header_len * 4)) {
+	    (package_header->header_len * 4)) {
 		DRM_ERROR("Firmware has wrong package header length %u bytes\n",
-			(package_header->header_len * 4));
-		goto out;
+			  (package_header->header_len * 4));
+		return NULL;
 	}
 	readcount += sizeof(struct intel_package_header);
 
 	/* Search for dmc_offset to find firware binary. */
 	for (i = 0; i < package_header->num_entries; i++) {
 		if (package_header->fw_info[i].substepping == '*' &&
-			stepping == package_header->fw_info[i].stepping) {
+		    stepping == package_header->fw_info[i].stepping) {
 			dmc_offset = package_header->fw_info[i].offset;
 			break;
 		} else if (stepping == package_header->fw_info[i].stepping &&
@@ -345,12 +302,12 @@
 			dmc_offset = package_header->fw_info[i].offset;
 			break;
 		} else if (package_header->fw_info[i].stepping == '*' &&
-			package_header->fw_info[i].substepping == '*')
+			   package_header->fw_info[i].substepping == '*')
 			dmc_offset = package_header->fw_info[i].offset;
 	}
 	if (dmc_offset == CSR_DEFAULT_FW_OFFSET) {
 		DRM_ERROR("Firmware not supported for %c stepping\n", stepping);
-		goto out;
+		return NULL;
 	}
 	readcount += dmc_offset;
 
@@ -358,26 +315,26 @@
 	dmc_header = (struct intel_dmc_header *)&fw->data[readcount];
 	if (sizeof(struct intel_dmc_header) != (dmc_header->header_len)) {
 		DRM_ERROR("Firmware has wrong dmc header length %u bytes\n",
-				(dmc_header->header_len));
-		goto out;
+			  (dmc_header->header_len));
+		return NULL;
 	}
 	readcount += sizeof(struct intel_dmc_header);
 
 	/* Cache the dmc header info. */
 	if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) {
 		DRM_ERROR("Firmware has wrong mmio count %u\n",
-						dmc_header->mmio_count);
-		goto out;
+			  dmc_header->mmio_count);
+		return NULL;
 	}
 	csr->mmio_count = dmc_header->mmio_count;
 	for (i = 0; i < dmc_header->mmio_count; i++) {
 		if (dmc_header->mmioaddr[i] < CSR_MMIO_START_RANGE ||
-			dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) {
+		    dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) {
 			DRM_ERROR(" Firmware has wrong mmio address 0x%x\n",
-						dmc_header->mmioaddr[i]);
-			goto out;
+				  dmc_header->mmioaddr[i]);
+			return NULL;
 		}
-		csr->mmioaddr[i] = dmc_header->mmioaddr[i];
+		csr->mmioaddr[i] = _MMIO(dmc_header->mmioaddr[i]);
 		csr->mmiodata[i] = dmc_header->mmiodata[i];
 	}
 
@@ -385,56 +342,80 @@
 	nbytes = dmc_header->fw_size * 4;
 	if (nbytes > CSR_MAX_FW_SIZE) {
 		DRM_ERROR("CSR firmware too big (%u) bytes\n", nbytes);
-		goto out;
+		return NULL;
 	}
 	csr->dmc_fw_size = dmc_header->fw_size;
 
-	csr->dmc_payload = kmalloc(nbytes, GFP_KERNEL);
-	if (!csr->dmc_payload) {
+	dmc_payload = kmalloc(nbytes, GFP_KERNEL);
+	if (!dmc_payload) {
 		DRM_ERROR("Memory allocation failed for dmc payload\n");
-		goto out;
+		return NULL;
 	}
 
-	dmc_payload = csr->dmc_payload;
 	memcpy(dmc_payload, &fw->data[readcount], nbytes);
 
-	/* load csr program during system boot, as needed for DC states */
-	intel_csr_load_program(dev);
-	fw_loaded = true;
+	return dmc_payload;
+}
 
-	DRM_DEBUG_KMS("Finished loading %s\n", dev_priv->csr.fw_path);
+static void csr_load_work_fn(struct work_struct *work)
+{
+	struct drm_i915_private *dev_priv;
+	struct intel_csr *csr;
+	const struct firmware *fw;
+	int ret;
+
+	dev_priv = container_of(work, typeof(*dev_priv), csr.work);
+	csr = &dev_priv->csr;
+
+	ret = request_firmware(&fw, dev_priv->csr.fw_path,
+			       &dev_priv->dev->pdev->dev);
+	if (!fw)
+		goto out;
+
+	dev_priv->csr.dmc_payload = parse_csr_fw(dev_priv, fw);
+	if (!dev_priv->csr.dmc_payload)
+		goto out;
+
+	/* load csr program during system boot, as needed for DC states */
+	intel_csr_load_program(dev_priv);
+
 out:
-	if (fw_loaded)
-		intel_runtime_pm_put(dev_priv);
-	else
-		intel_csr_load_status_set(dev_priv, FW_FAILED);
+	if (dev_priv->csr.dmc_payload) {
+		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+
+		DRM_INFO("Finished loading %s (v%u.%u)\n",
+			 dev_priv->csr.fw_path,
+			 CSR_VERSION_MAJOR(csr->version),
+			 CSR_VERSION_MINOR(csr->version));
+	} else {
+		DRM_ERROR("Failed to load DMC firmware, disabling rpm\n");
+	}
 
 	release_firmware(fw);
 }
 
 /**
  * intel_csr_ucode_init() - initialize the firmware loading.
- * @dev: drm device.
+ * @dev_priv: i915 drm device.
  *
  * This function is called at the time of loading the display driver to read
  * firmware from a .bin file and copied into a internal memory.
  */
-void intel_csr_ucode_init(struct drm_device *dev)
+void intel_csr_ucode_init(struct drm_i915_private *dev_priv)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_csr *csr = &dev_priv->csr;
-	int ret;
 
-	if (!HAS_CSR(dev))
+	INIT_WORK(&dev_priv->csr.work, csr_load_work_fn);
+
+	if (!HAS_CSR(dev_priv))
 		return;
 
-	if (IS_SKYLAKE(dev))
+	if (IS_SKYLAKE(dev_priv))
 		csr->fw_path = I915_CSR_SKL;
 	else if (IS_BROXTON(dev_priv))
 		csr->fw_path = I915_CSR_BXT;
 	else {
 		DRM_ERROR("Unexpected: no known CSR firmware for platform\n");
-		intel_csr_load_status_set(dev_priv, FW_FAILED);
 		return;
 	}
 
@@ -444,43 +425,24 @@
 	 * Obtain a runtime pm reference, until CSR is loaded,
 	 * to avoid entering runtime-suspend.
 	 */
-	intel_runtime_pm_get(dev_priv);
+	intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
 
-	/* CSR supported for platform, load firmware */
-	ret = request_firmware_nowait(THIS_MODULE, true, csr->fw_path,
-				&dev_priv->dev->pdev->dev,
-				GFP_KERNEL, dev_priv,
-				finish_csr_load);
-	if (ret) {
-		i915_firmware_load_error_print(csr->fw_path, ret);
-		intel_csr_load_status_set(dev_priv, FW_FAILED);
-	}
+	schedule_work(&dev_priv->csr.work);
 }
 
 /**
  * intel_csr_ucode_fini() - unload the CSR firmware.
- * @dev: drm device.
+ * @dev_priv: i915 drm device.
  *
  * Firmmware unloading includes freeing the internal momory and reset the
  * firmware loading status.
  */
-void intel_csr_ucode_fini(struct drm_device *dev)
+void intel_csr_ucode_fini(struct drm_i915_private *dev_priv)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	if (!HAS_CSR(dev))
+	if (!HAS_CSR(dev_priv))
 		return;
 
-	intel_csr_load_status_set(dev_priv, FW_FAILED);
-	kfree(dev_priv->csr.dmc_payload);
-}
+	flush_work(&dev_priv->csr.work);
 
-void assert_csr_loaded(struct drm_i915_private *dev_priv)
-{
-	WARN_ONCE(intel_csr_load_status_get(dev_priv) != FW_LOADED,
-		  "CSR is not loaded.\n");
-	WARN_ONCE(!I915_READ(CSR_PROGRAM(0)),
-		  "CSR program storage start is NULL\n");
-	WARN_ONCE(!I915_READ(CSR_SSP_BASE), "CSR SSP Base Not fine\n");
-	WARN_ONCE(!I915_READ(CSR_HTP_SKL), "CSR HTP Not fine\n");
+	kfree(dev_priv->csr.dmc_payload);
 }
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index a6752a6..59deb0d 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -133,12 +133,12 @@
 	{ 0x00002016, 0x000000A0, 0x0 },
 	{ 0x00005012, 0x0000009B, 0x0 },
 	{ 0x00007011, 0x00000088, 0x0 },
-	{ 0x00009010, 0x000000C7, 0x0 },
+	{ 0x80009010, 0x000000C0, 0x1 },	/* Uses I_boost level 0x1 */
 	{ 0x00002016, 0x0000009B, 0x0 },
 	{ 0x00005012, 0x00000088, 0x0 },
-	{ 0x00007011, 0x000000C7, 0x0 },
+	{ 0x80007011, 0x000000C0, 0x1 },	/* Uses I_boost level 0x1 */
 	{ 0x00002016, 0x000000DF, 0x0 },
-	{ 0x00005012, 0x000000C7, 0x0 },
+	{ 0x80005012, 0x000000C0, 0x1 },	/* Uses I_boost level 0x1 */
 };
 
 /* Skylake U */
@@ -146,12 +146,12 @@
 	{ 0x0000201B, 0x000000A2, 0x0 },
 	{ 0x00005012, 0x00000088, 0x0 },
 	{ 0x00007011, 0x00000087, 0x0 },
-	{ 0x80009010, 0x000000C7, 0x1 },	/* Uses I_boost level 0x1 */
+	{ 0x80009010, 0x000000C0, 0x1 },	/* Uses I_boost level 0x1 */
 	{ 0x0000201B, 0x0000009D, 0x0 },
-	{ 0x00005012, 0x000000C7, 0x0 },
-	{ 0x00007011, 0x000000C7, 0x0 },
+	{ 0x80005012, 0x000000C0, 0x1 },	/* Uses I_boost level 0x1 */
+	{ 0x80007011, 0x000000C0, 0x1 },	/* Uses I_boost level 0x1 */
 	{ 0x00002016, 0x00000088, 0x0 },
-	{ 0x00005012, 0x000000C7, 0x0 },
+	{ 0x80005012, 0x000000C0, 0x1 },	/* Uses I_boost level 0x1 */
 };
 
 /* Skylake Y */
@@ -159,12 +159,12 @@
 	{ 0x00000018, 0x000000A2, 0x0 },
 	{ 0x00005012, 0x00000088, 0x0 },
 	{ 0x00007011, 0x00000087, 0x0 },
-	{ 0x80009010, 0x000000C7, 0x3 },	/* Uses I_boost level 0x3 */
+	{ 0x80009010, 0x000000C0, 0x3 },	/* Uses I_boost level 0x3 */
 	{ 0x00000018, 0x0000009D, 0x0 },
-	{ 0x00005012, 0x000000C7, 0x0 },
-	{ 0x00007011, 0x000000C7, 0x0 },
+	{ 0x80005012, 0x000000C0, 0x3 },	/* Uses I_boost level 0x3 */
+	{ 0x80007011, 0x000000C0, 0x3 },	/* Uses I_boost level 0x3 */
 	{ 0x00000018, 0x00000088, 0x0 },
-	{ 0x00005012, 0x000000C7, 0x0 },
+	{ 0x80005012, 0x000000C0, 0x3 },	/* Uses I_boost level 0x3 */
 };
 
 /*
@@ -345,7 +345,7 @@
 static bool
 intel_dig_port_supports_hdmi(const struct intel_digital_port *intel_dig_port)
 {
-	return intel_dig_port->hdmi.hdmi_reg;
+	return i915_mmio_reg_valid(intel_dig_port->hdmi.hdmi_reg);
 }
 
 static const struct ddi_buf_trans *skl_get_buf_trans_dp(struct drm_device *dev,
@@ -448,7 +448,7 @@
 		bxt_ddi_vswing_sequence(dev, hdmi_level, port,
 					INTEL_OUTPUT_HDMI);
 		return;
-	} else if (IS_SKYLAKE(dev)) {
+	} else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
 		ddi_translations_fdi = NULL;
 		ddi_translations_dp =
 				skl_get_buf_trans_dp(dev, &n_dp_entries);
@@ -576,7 +576,7 @@
 static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
 				    enum port port)
 {
-	uint32_t reg = DDI_BUF_CTL(port);
+	i915_reg_t reg = DDI_BUF_CTL(port);
 	int i;
 
 	for (i = 0; i < 16; i++) {
@@ -931,7 +931,8 @@
 	/* Otherwise a < c && b >= d, do nothing */
 }
 
-static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, int reg)
+static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
+				   i915_reg_t reg)
 {
 	int refclk = LC_FREQ;
 	int n, p, r;
@@ -967,7 +968,7 @@
 static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv,
 			       uint32_t dpll)
 {
-	uint32_t cfgcr1_reg, cfgcr2_reg;
+	i915_reg_t cfgcr1_reg, cfgcr2_reg;
 	uint32_t cfgcr1_val, cfgcr2_val;
 	uint32_t p0, p1, p2, dco_freq;
 
@@ -1112,10 +1113,10 @@
 		link_clock = 270000;
 		break;
 	case PORT_CLK_SEL_WRPLL1:
-		link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL1);
+		link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL(0));
 		break;
 	case PORT_CLK_SEL_WRPLL2:
-		link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL2);
+		link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL(1));
 		break;
 	case PORT_CLK_SEL_SPLL:
 		pll = I915_READ(SPLL_CTL) & SPLL_PLL_FREQ_MASK;
@@ -1184,7 +1185,7 @@
 
 	if (INTEL_INFO(dev)->gen <= 8)
 		hsw_ddi_clock_get(encoder, pipe_config);
-	else if (IS_SKYLAKE(dev))
+	else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
 		skl_ddi_clock_get(encoder, pipe_config);
 	else if (IS_BROXTON(dev))
 		bxt_ddi_clock_get(encoder, pipe_config);
@@ -1780,7 +1781,7 @@
 	struct intel_encoder *intel_encoder =
 		intel_ddi_get_crtc_new_encoder(crtc_state);
 
-	if (IS_SKYLAKE(dev))
+	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
 		return skl_ddi_pll_select(intel_crtc, crtc_state,
 					  intel_encoder);
 	else if (IS_BROXTON(dev))
@@ -1942,7 +1943,7 @@
 void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
 				       enum transcoder cpu_transcoder)
 {
-	uint32_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder);
+	i915_reg_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder);
 	uint32_t val = I915_READ(reg);
 
 	val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK | TRANS_DDI_DP_VC_PAYLOAD_ALLOC);
@@ -2097,21 +2098,21 @@
 			iboost = dp_iboost;
 		} else {
 			ddi_translations = skl_get_buf_trans_dp(dev, &n_entries);
-			iboost = ddi_translations[port].i_boost;
+			iboost = ddi_translations[level].i_boost;
 		}
 	} else if (type == INTEL_OUTPUT_EDP) {
 		if (dp_iboost) {
 			iboost = dp_iboost;
 		} else {
 			ddi_translations = skl_get_buf_trans_edp(dev, &n_entries);
-			iboost = ddi_translations[port].i_boost;
+			iboost = ddi_translations[level].i_boost;
 		}
 	} else if (type == INTEL_OUTPUT_HDMI) {
 		if (hdmi_iboost) {
 			iboost = hdmi_iboost;
 		} else {
 			ddi_translations = skl_get_buf_trans_hdmi(dev, &n_entries);
-			iboost = ddi_translations[port].i_boost;
+			iboost = ddi_translations[level].i_boost;
 		}
 	} else {
 		return;
@@ -2263,7 +2264,7 @@
 
 	level = translate_signal_level(signal_levels);
 
-	if (IS_SKYLAKE(dev))
+	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
 		skl_ddi_set_iboost(dev, level, port, encoder->type);
 	else if (IS_BROXTON(dev))
 		bxt_ddi_vswing_sequence(dev, level, port, encoder->type);
@@ -2271,6 +2272,50 @@
 	return DDI_BUF_TRANS_SELECT(level);
 }
 
+void intel_ddi_clk_select(struct intel_encoder *encoder,
+			  const struct intel_crtc_state *pipe_config)
+{
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	enum port port = intel_ddi_get_encoder_port(encoder);
+
+	if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+		uint32_t dpll = pipe_config->ddi_pll_sel;
+		uint32_t val;
+
+		/*
+		 * DPLL0 is used for eDP and is the only "private" DPLL (as
+		 * opposed to shared) on SKL
+		 */
+		if (encoder->type == INTEL_OUTPUT_EDP) {
+			WARN_ON(dpll != SKL_DPLL0);
+
+			val = I915_READ(DPLL_CTRL1);
+
+			val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) |
+				 DPLL_CTRL1_SSC(dpll) |
+				 DPLL_CTRL1_LINK_RATE_MASK(dpll));
+			val |= pipe_config->dpll_hw_state.ctrl1 << (dpll * 6);
+
+			I915_WRITE(DPLL_CTRL1, val);
+			POSTING_READ(DPLL_CTRL1);
+		}
+
+		/* DDI -> PLL mapping  */
+		val = I915_READ(DPLL_CTRL2);
+
+		val &= ~(DPLL_CTRL2_DDI_CLK_OFF(port) |
+			DPLL_CTRL2_DDI_CLK_SEL_MASK(port));
+		val |= (DPLL_CTRL2_DDI_CLK_SEL(dpll, port) |
+			DPLL_CTRL2_DDI_SEL_OVERRIDE(port));
+
+		I915_WRITE(DPLL_CTRL2, val);
+
+	} else if (INTEL_INFO(dev_priv)->gen < 9) {
+		WARN_ON(pipe_config->ddi_pll_sel == PORT_CLK_SEL_NONE);
+		I915_WRITE(PORT_CLK_SEL(port), pipe_config->ddi_pll_sel);
+	}
+}
+
 static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 {
 	struct drm_encoder *encoder = &intel_encoder->base;
@@ -2286,42 +2331,7 @@
 		intel_edp_panel_on(intel_dp);
 	}
 
-	if (IS_SKYLAKE(dev)) {
-		uint32_t dpll = crtc->config->ddi_pll_sel;
-		uint32_t val;
-
-		/*
-		 * DPLL0 is used for eDP and is the only "private" DPLL (as
-		 * opposed to shared) on SKL
-		 */
-		if (type == INTEL_OUTPUT_EDP) {
-			WARN_ON(dpll != SKL_DPLL0);
-
-			val = I915_READ(DPLL_CTRL1);
-
-			val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) |
-				 DPLL_CTRL1_SSC(dpll) |
-				 DPLL_CTRL1_LINK_RATE_MASK(dpll));
-			val |= crtc->config->dpll_hw_state.ctrl1 << (dpll * 6);
-
-			I915_WRITE(DPLL_CTRL1, val);
-			POSTING_READ(DPLL_CTRL1);
-		}
-
-		/* DDI -> PLL mapping  */
-		val = I915_READ(DPLL_CTRL2);
-
-		val &= ~(DPLL_CTRL2_DDI_CLK_OFF(port) |
-			DPLL_CTRL2_DDI_CLK_SEL_MASK(port));
-		val |= (DPLL_CTRL2_DDI_CLK_SEL(dpll, port) |
-			DPLL_CTRL2_DDI_SEL_OVERRIDE(port));
-
-		I915_WRITE(DPLL_CTRL2, val);
-
-	} else if (INTEL_INFO(dev)->gen < 9) {
-		WARN_ON(crtc->config->ddi_pll_sel == PORT_CLK_SEL_NONE);
-		I915_WRITE(PORT_CLK_SEL(port), crtc->config->ddi_pll_sel);
-	}
+	intel_ddi_clk_select(intel_encoder, crtc->config);
 
 	if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
@@ -2381,7 +2391,7 @@
 		intel_edp_panel_off(intel_dp);
 	}
 
-	if (IS_SKYLAKE(dev))
+	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
 		I915_WRITE(DPLL_CTRL2, (I915_READ(DPLL_CTRL2) |
 					DPLL_CTRL2_DDI_CLK_OFF(port)));
 	else if (INTEL_INFO(dev)->gen < 9)
@@ -2553,7 +2563,7 @@
 };
 
 struct skl_dpll_regs {
-	u32 ctl, cfgcr1, cfgcr2;
+	i915_reg_t ctl, cfgcr1, cfgcr2;
 };
 
 /* this array is indexed by the *shared* pll id */
@@ -2566,13 +2576,13 @@
 	},
 	{
 		/* DPLL 2 */
-		.ctl = WRPLL_CTL1,
+		.ctl = WRPLL_CTL(0),
 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL2),
 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL2),
 	},
 	{
 		/* DPLL 3 */
-		.ctl = WRPLL_CTL2,
+		.ctl = WRPLL_CTL(1),
 		.cfgcr1 = DPLL_CFGCR1(SKL_DPLL3),
 		.cfgcr2 = DPLL_CFGCR2(SKL_DPLL3),
 	},
@@ -2992,22 +3002,22 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	uint32_t val = I915_READ(LCPLL_CTL);
 
-	if (IS_SKYLAKE(dev))
+	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
 		skl_shared_dplls_init(dev_priv);
 	else if (IS_BROXTON(dev))
 		bxt_shared_dplls_init(dev_priv);
 	else
 		hsw_shared_dplls_init(dev_priv);
 
-	if (IS_SKYLAKE(dev)) {
+	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
 		int cdclk_freq;
 
 		cdclk_freq = dev_priv->display.get_display_clock_speed(dev);
 		dev_priv->skl_boot_cdclk = cdclk_freq;
+		if (skl_sanitize_cdclk(dev_priv))
+			DRM_DEBUG_KMS("Sanitized cdclk programmed by pre-os\n");
 		if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE))
 			DRM_ERROR("LCPLL1 is disabled\n");
-		else
-			intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
 	} else if (IS_BROXTON(dev)) {
 		broxton_init_cdclk(dev);
 		broxton_ddi_phy_init(dev);
@@ -3026,11 +3036,11 @@
 	}
 }
 
-void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder)
+void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
 {
-	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
-	struct intel_dp *intel_dp = &intel_dig_port->dp;
-	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_i915_private *dev_priv =
+		to_i915(intel_dig_port->base.base.dev);
 	enum port port = intel_dig_port->port;
 	uint32_t val;
 	bool wait = false;
@@ -3285,10 +3295,25 @@
 	intel_encoder->get_config = intel_ddi_get_config;
 
 	intel_dig_port->port = port;
+	dev_priv->dig_port_map[port] = intel_encoder;
 	intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
 					  (DDI_BUF_PORT_REVERSAL |
 					   DDI_A_4_LANES);
 
+	/*
+	 * Bspec says that DDI_A_4_LANES is the only supported configuration
+	 * for Broxton.  Yet some BIOS fail to set this bit on port A if eDP
+	 * wasn't lit up at boot.  Force this bit on in our internal
+	 * configuration so that we use the proper lane count for our
+	 * calculations.
+	 */
+	if (IS_BROXTON(dev) && port == PORT_A) {
+		if (!(intel_dig_port->saved_port_bits & DDI_A_4_LANES)) {
+			DRM_DEBUG_KMS("BXT BIOS forgot to set DDI_A_4_LANES for port A; fixing\n");
+			intel_dig_port->saved_port_bits |= DDI_A_4_LANES;
+		}
+	}
+
 	intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
 	intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
 	intel_encoder->cloneable = 0;
@@ -3302,8 +3327,7 @@
 		 * On BXT A0/A1, sw needs to activate DDIA HPD logic and
 		 * interrupts to check the external panel connection.
 		 */
-		if (IS_BROXTON(dev_priv) && (INTEL_REVID(dev) < BXT_REVID_B0)
-					 && port == PORT_B)
+		if (IS_BXT_REVID(dev, 0, BXT_REVID_A1) && port == PORT_B)
 			dev_priv->hotplug.irq_port[PORT_A] = intel_dig_port;
 		else
 			dev_priv->hotplug.irq_port[port] = intel_dig_port;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 32cf973..622d30c 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1096,7 +1096,7 @@
 static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 reg = PIPEDSL(pipe);
+	i915_reg_t reg = PIPEDSL(pipe);
 	u32 line1, line2;
 	u32 line_mask;
 
@@ -1136,7 +1136,7 @@
 	enum pipe pipe = crtc->pipe;
 
 	if (INTEL_INFO(dev)->gen >= 4) {
-		int reg = PIPECONF(cpu_transcoder);
+		i915_reg_t reg = PIPECONF(cpu_transcoder);
 
 		/* Wait for the Pipe State to go off */
 		if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0,
@@ -1286,7 +1286,7 @@
 			   enum pipe pipe)
 {
 	struct drm_device *dev = dev_priv->dev;
-	int pp_reg;
+	i915_reg_t pp_reg;
 	u32 val;
 	enum pipe panel_pipe = PIPE_A;
 	bool locked = true;
@@ -1481,8 +1481,7 @@
 		return false;
 
 	if (HAS_PCH_CPT(dev_priv->dev)) {
-		u32	trans_dp_ctl_reg = TRANS_DP_CTL(pipe);
-		u32	trans_dp_ctl = I915_READ(trans_dp_ctl_reg);
+		u32 trans_dp_ctl = I915_READ(TRANS_DP_CTL(pipe));
 		if ((trans_dp_ctl & TRANS_DP_PORT_SEL_MASK) != port_sel)
 			return false;
 	} else if (IS_CHERRYVIEW(dev_priv->dev)) {
@@ -1546,12 +1545,13 @@
 }
 
 static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
-				   enum pipe pipe, int reg, u32 port_sel)
+				   enum pipe pipe, i915_reg_t reg,
+				   u32 port_sel)
 {
 	u32 val = I915_READ(reg);
 	I915_STATE_WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),
 	     "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
-	     reg, pipe_name(pipe));
+	     i915_mmio_reg_offset(reg), pipe_name(pipe));
 
 	I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0
 	     && (val & DP_PIPEB_SELECT),
@@ -1559,12 +1559,12 @@
 }
 
 static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
-				     enum pipe pipe, int reg)
+				     enum pipe pipe, i915_reg_t reg)
 {
 	u32 val = I915_READ(reg);
 	I915_STATE_WARN(hdmi_pipe_enabled(dev_priv, pipe, val),
 	     "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n",
-	     reg, pipe_name(pipe));
+	     i915_mmio_reg_offset(reg), pipe_name(pipe));
 
 	I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0
 	     && (val & SDVO_PIPE_B_SELECT),
@@ -1600,7 +1600,7 @@
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	int reg = DPLL(crtc->pipe);
+	i915_reg_t reg = DPLL(crtc->pipe);
 	u32 dpll = pipe_config->dpll_hw_state.dpll;
 
 	assert_pipe_disabled(dev_priv, crtc->pipe);
@@ -1689,7 +1689,7 @@
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	int reg = DPLL(crtc->pipe);
+	i915_reg_t reg = DPLL(crtc->pipe);
 	u32 dpll = crtc->config->dpll_hw_state.dpll;
 
 	assert_pipe_disabled(dev_priv, crtc->pipe);
@@ -1838,7 +1838,7 @@
 			 unsigned int expected_mask)
 {
 	u32 port_mask;
-	int dpll_reg;
+	i915_reg_t dpll_reg;
 
 	switch (dport->port) {
 	case PORT_B:
@@ -1963,7 +1963,8 @@
 	struct drm_device *dev = dev_priv->dev;
 	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	uint32_t reg, val, pipeconf_val;
+	i915_reg_t reg;
+	uint32_t val, pipeconf_val;
 
 	/* PCH only available on ILK+ */
 	BUG_ON(!HAS_PCH_SPLIT(dev));
@@ -2052,7 +2053,8 @@
 					    enum pipe pipe)
 {
 	struct drm_device *dev = dev_priv->dev;
-	uint32_t reg, val;
+	i915_reg_t reg;
+	uint32_t val;
 
 	/* FDI relies on the transcoder */
 	assert_fdi_tx_disabled(dev_priv, pipe);
@@ -2069,7 +2071,7 @@
 	if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50))
 		DRM_ERROR("failed to disable transcoder %c\n", pipe_name(pipe));
 
-	if (!HAS_PCH_IBX(dev)) {
+	if (HAS_PCH_CPT(dev)) {
 		/* Workaround: Clear the timing override chicken bit again. */
 		reg = TRANS_CHICKEN2(pipe);
 		val = I915_READ(reg);
@@ -2107,10 +2109,9 @@
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	enum pipe pipe = crtc->pipe;
-	enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
-								      pipe);
+	enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
 	enum pipe pch_transcoder;
-	int reg;
+	i915_reg_t reg;
 	u32 val;
 
 	DRM_DEBUG_KMS("enabling pipe %c\n", pipe_name(pipe));
@@ -2171,7 +2172,7 @@
 	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
 	enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
 	enum pipe pipe = crtc->pipe;
-	int reg;
+	i915_reg_t reg;
 	u32 val;
 
 	DRM_DEBUG_KMS("disabling pipe %c\n", pipe_name(pipe));
@@ -2270,20 +2271,20 @@
 					       fb_format_modifier, 0));
 }
 
-static int
+static void
 intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb,
 			const struct drm_plane_state *plane_state)
 {
-	struct intel_rotation_info *info = &view->rotation_info;
+	struct intel_rotation_info *info = &view->params.rotation_info;
 	unsigned int tile_height, tile_pitch;
 
 	*view = i915_ggtt_view_normal;
 
 	if (!plane_state)
-		return 0;
+		return;
 
 	if (!intel_rotation_90_or_270(plane_state->rotation))
-		return 0;
+		return;
 
 	*view = i915_ggtt_view_rotated;
 
@@ -2310,8 +2311,6 @@
 		info->size_uv = info->width_pages_uv * info->height_pages_uv *
 				PAGE_SIZE;
 	}
-
-	return 0;
 }
 
 static unsigned int intel_linear_alignment(struct drm_i915_private *dev_priv)
@@ -2330,9 +2329,7 @@
 int
 intel_pin_and_fence_fb_obj(struct drm_plane *plane,
 			   struct drm_framebuffer *fb,
-			   const struct drm_plane_state *plane_state,
-			   struct intel_engine_cs *pipelined,
-			   struct drm_i915_gem_request **pipelined_request)
+			   const struct drm_plane_state *plane_state)
 {
 	struct drm_device *dev = fb->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2367,9 +2364,7 @@
 		return -EINVAL;
 	}
 
-	ret = intel_fill_fb_ggtt_view(&view, fb, plane_state);
-	if (ret)
-		return ret;
+	intel_fill_fb_ggtt_view(&view, fb, plane_state);
 
 	/* Note that the w/a also requires 64 PTE of padding following the
 	 * bo. We currently fill all unused PTE with the shadow page and so
@@ -2388,11 +2383,10 @@
 	 */
 	intel_runtime_pm_get(dev_priv);
 
-	dev_priv->mm.interruptible = false;
-	ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined,
-						   pipelined_request, &view);
+	ret = i915_gem_object_pin_to_display_plane(obj, alignment,
+						   &view);
 	if (ret)
-		goto err_interruptible;
+		goto err_pm;
 
 	/* Install a fence for tiled scan-out. Pre-i965 always needs a
 	 * fence, whereas 965+ only requires a fence if using
@@ -2418,14 +2412,12 @@
 		i915_gem_object_pin_fence(obj);
 	}
 
-	dev_priv->mm.interruptible = true;
 	intel_runtime_pm_put(dev_priv);
 	return 0;
 
 err_unpin:
 	i915_gem_object_unpin_from_display_plane(obj, &view);
-err_interruptible:
-	dev_priv->mm.interruptible = true;
+err_pm:
 	intel_runtime_pm_put(dev_priv);
 	return ret;
 }
@@ -2435,12 +2427,10 @@
 {
 	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 	struct i915_ggtt_view view;
-	int ret;
 
 	WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex));
 
-	ret = intel_fill_fb_ggtt_view(&view, fb, plane_state);
-	WARN_ONCE(ret, "Couldn't get view from plane state!");
+	intel_fill_fb_ggtt_view(&view, fb, plane_state);
 
 	if (view.type == I915_GGTT_VIEW_NORMAL)
 		i915_gem_object_unpin_fence(obj);
@@ -2695,7 +2685,7 @@
 	int plane = intel_crtc->plane;
 	unsigned long linear_offset;
 	u32 dspcntr;
-	u32 reg = DSPCNTR(plane);
+	i915_reg_t reg = DSPCNTR(plane);
 	int pixel_size;
 
 	if (!visible || !fb) {
@@ -2825,7 +2815,7 @@
 	int plane = intel_crtc->plane;
 	unsigned long linear_offset;
 	u32 dspcntr;
-	u32 reg = DSPCNTR(plane);
+	i915_reg_t reg = DSPCNTR(plane);
 	int pixel_size;
 
 	if (!visible || !fb) {
@@ -2950,30 +2940,32 @@
 	}
 }
 
-unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
-				     struct drm_i915_gem_object *obj,
-				     unsigned int plane)
+u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
+			   struct drm_i915_gem_object *obj,
+			   unsigned int plane)
 {
-	const struct i915_ggtt_view *view = &i915_ggtt_view_normal;
+	struct i915_ggtt_view view;
 	struct i915_vma *vma;
-	unsigned char *offset;
+	u64 offset;
 
-	if (intel_rotation_90_or_270(intel_plane->base.state->rotation))
-		view = &i915_ggtt_view_rotated;
+	intel_fill_fb_ggtt_view(&view, intel_plane->base.fb,
+				intel_plane->base.state);
 
-	vma = i915_gem_obj_to_ggtt_view(obj, view);
+	vma = i915_gem_obj_to_ggtt_view(obj, &view);
 	if (WARN(!vma, "ggtt vma for display object not found! (view=%u)\n",
-		view->type))
+		view.type))
 		return -1;
 
-	offset = (unsigned char *)vma->node.start;
+	offset = vma->node.start;
 
 	if (plane == 1) {
-		offset += vma->ggtt_view.rotation_info.uv_start_page *
+		offset += vma->ggtt_view.params.rotation_info.uv_start_page *
 			  PAGE_SIZE;
 	}
 
-	return (unsigned long)offset;
+	WARN_ON(upper_32_bits(offset));
+
+	return lower_32_bits(offset);
 }
 
 static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
@@ -3099,7 +3091,7 @@
 	u32 tile_height, plane_offset, plane_size;
 	unsigned int rotation;
 	int x_offset, y_offset;
-	unsigned long surf_addr;
+	u32 surf_addr;
 	struct intel_crtc_state *crtc_state = intel_crtc->config;
 	struct intel_plane_state *plane_state;
 	int src_x = 0, src_y = 0, src_w = 0, src_h = 0;
@@ -3227,10 +3219,9 @@
 		struct intel_plane_state *plane_state;
 
 		drm_modeset_lock_crtc(crtc, &plane->base);
-
 		plane_state = to_intel_plane_state(plane->base.state);
 
-		if (plane_state->base.fb)
+		if (crtc->state->active && plane_state->base.fb)
 			plane->commit_plane(&plane->base, plane_state);
 
 		drm_modeset_unlock_crtc(crtc);
@@ -3306,32 +3297,6 @@
 	drm_modeset_unlock_all(dev);
 }
 
-static void
-intel_finish_fb(struct drm_framebuffer *old_fb)
-{
-	struct drm_i915_gem_object *obj = intel_fb_obj(old_fb);
-	struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
-	bool was_interruptible = dev_priv->mm.interruptible;
-	int ret;
-
-	/* Big Hammer, we also need to ensure that any pending
-	 * MI_WAIT_FOR_EVENT inside a user batch buffer on the
-	 * current scanout is retired before unpinning the old
-	 * framebuffer. Note that we rely on userspace rendering
-	 * into the buffer attached to the pipe they are waiting
-	 * on. If not, userspace generates a GPU hang with IPEHR
-	 * point to the MI_WAIT_FOR_EVENT.
-	 *
-	 * This should only fail upon a hung GPU, in which case we
-	 * can safely continue.
-	 */
-	dev_priv->mm.interruptible = false;
-	ret = i915_gem_object_wait_rendering(obj, true);
-	dev_priv->mm.interruptible = was_interruptible;
-
-	WARN_ON(ret);
-}
-
 static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
@@ -3401,7 +3366,8 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
-	u32 reg, temp;
+	i915_reg_t reg;
+	u32 temp;
 
 	/* enable normal train */
 	reg = FDI_TX_CTL(pipe);
@@ -3443,7 +3409,8 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
-	u32 reg, temp, tries;
+	i915_reg_t reg;
+	u32 temp, tries;
 
 	/* FDI needs bits from pipe first */
 	assert_pipe_enabled(dev_priv, pipe);
@@ -3543,7 +3510,8 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
-	u32 reg, temp, i, retry;
+	i915_reg_t reg;
+	u32 temp, i, retry;
 
 	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
 	   for train result */
@@ -3675,7 +3643,8 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
-	u32 reg, temp, i, j;
+	i915_reg_t reg;
+	u32 temp, i, j;
 
 	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
 	   for train result */
@@ -3792,8 +3761,8 @@
 	struct drm_device *dev = intel_crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int pipe = intel_crtc->pipe;
-	u32 reg, temp;
-
+	i915_reg_t reg;
+	u32 temp;
 
 	/* enable PCH FDI RX PLL, wait warmup plus DMI latency */
 	reg = FDI_RX_CTL(pipe);
@@ -3829,7 +3798,8 @@
 	struct drm_device *dev = intel_crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int pipe = intel_crtc->pipe;
-	u32 reg, temp;
+	i915_reg_t reg;
+	u32 temp;
 
 	/* Switch from PCDclk to Rawclk */
 	reg = FDI_RX_CTL(pipe);
@@ -3859,7 +3829,8 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
-	u32 reg, temp;
+	i915_reg_t reg;
+	u32 temp;
 
 	/* disable CPU FDI tx and PCH FDI rx */
 	reg = FDI_TX_CTL(pipe);
@@ -3952,15 +3923,23 @@
 				 work->pending_flip_obj);
 }
 
-void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
+static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	long ret;
 
 	WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue));
-	if (WARN_ON(wait_event_timeout(dev_priv->pending_flip_queue,
-				       !intel_crtc_has_pending_flip(crtc),
-				       60*HZ) == 0)) {
+
+	ret = wait_event_interruptible_timeout(
+					dev_priv->pending_flip_queue,
+					!intel_crtc_has_pending_flip(crtc),
+					60*HZ);
+
+	if (ret < 0)
+		return ret;
+
+	if (ret == 0) {
 		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
 		spin_lock_irq(&dev->event_lock);
@@ -3971,11 +3950,7 @@
 		spin_unlock_irq(&dev->event_lock);
 	}
 
-	if (crtc->primary->fb) {
-		mutex_lock(&dev->struct_mutex);
-		intel_finish_fb(crtc->primary->fb);
-		mutex_unlock(&dev->struct_mutex);
-	}
+	return 0;
 }
 
 /* Program iCLKIP clock to the desired frequency */
@@ -4135,6 +4110,22 @@
 	}
 }
 
+/* Return which DP Port should be selected for Transcoder DP control */
+static enum port
+intel_trans_dp_port_sel(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct intel_encoder *encoder;
+
+	for_each_encoder_on_crtc(dev, crtc, encoder) {
+		if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+		    encoder->type == INTEL_OUTPUT_EDP)
+			return enc_to_dig_port(&encoder->base)->port;
+	}
+
+	return -1;
+}
+
 /*
  * Enable PCH resources required for PCH ports:
  *   - PCH PLLs
@@ -4149,7 +4140,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
-	u32 reg, temp;
+	u32 temp;
 
 	assert_pch_transcoder_disabled(dev_priv, pipe);
 
@@ -4196,8 +4187,10 @@
 
 	/* For PCH DP, enable TRANS_DP_CTL */
 	if (HAS_PCH_CPT(dev) && intel_crtc->config->has_dp_encoder) {
+		const struct drm_display_mode *adjusted_mode =
+			&intel_crtc->config->base.adjusted_mode;
 		u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) >> 5;
-		reg = TRANS_DP_CTL(pipe);
+		i915_reg_t reg = TRANS_DP_CTL(pipe);
 		temp = I915_READ(reg);
 		temp &= ~(TRANS_DP_PORT_SEL_MASK |
 			  TRANS_DP_SYNC_MASK |
@@ -4205,19 +4198,19 @@
 		temp |= TRANS_DP_OUTPUT_ENABLE;
 		temp |= bpc << 9; /* same format but at 11:9 */
 
-		if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
+		if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
 			temp |= TRANS_DP_HSYNC_ACTIVE_HIGH;
-		if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
+		if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
 			temp |= TRANS_DP_VSYNC_ACTIVE_HIGH;
 
 		switch (intel_trans_dp_port_sel(crtc)) {
-		case PCH_DP_B:
+		case PORT_B:
 			temp |= TRANS_DP_PORT_SEL_B;
 			break;
-		case PCH_DP_C:
+		case PORT_C:
 			temp |= TRANS_DP_PORT_SEL_C;
 			break;
-		case PCH_DP_D:
+		case PORT_D:
 			temp |= TRANS_DP_PORT_SEL_D;
 			break;
 		default:
@@ -4357,7 +4350,7 @@
 static void cpt_verify_modeset(struct drm_device *dev, int pipe)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	int dslreg = PIPEDSL(pipe);
+	i915_reg_t dslreg = PIPEDSL(pipe);
 	u32 temp;
 
 	temp = I915_READ(dslreg);
@@ -4667,7 +4660,7 @@
 	}
 
 	for (i = 0; i < 256; i++) {
-		u32 palreg;
+		i915_reg_t palreg;
 
 		if (HAS_GMCH_DISPLAY(dev))
 			palreg = PALETTE(pipe, i);
@@ -4746,9 +4739,9 @@
 	if (IS_GEN2(dev))
 		intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
 
-	/* Underruns don't raise interrupts, so check manually. */
-	if (HAS_GMCH_DISPLAY(dev))
-		i9xx_check_fifo_underruns(dev_priv);
+	/* Underruns don't always raise interrupts, so check manually. */
+	intel_check_cpu_fifo_underruns(dev_priv);
+	intel_check_pch_fifo_underruns(dev_priv);
 }
 
 /**
@@ -4807,7 +4800,6 @@
 	struct intel_crtc_atomic_commit *atomic = &crtc->atomic;
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_plane *plane;
 
 	if (atomic->wait_vblank)
 		intel_wait_for_vblank(dev, crtc->pipe);
@@ -4826,10 +4818,6 @@
 	if (atomic->post_enable_primary)
 		intel_post_enable_primary(&crtc->base);
 
-	drm_for_each_plane_mask(plane, dev, atomic->update_sprite_watermarks)
-		intel_update_sprite_watermarks(plane, &crtc->base,
-					       0, 0, 0, false, false);
-
 	memset(atomic, 0, sizeof(*atomic));
 }
 
@@ -4838,20 +4826,6 @@
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc_atomic_commit *atomic = &crtc->atomic;
-	struct drm_plane *p;
-
-	/* Track fb's for any planes being disabled */
-	drm_for_each_plane_mask(p, dev, atomic->disabled_planes) {
-		struct intel_plane *plane = to_intel_plane(p);
-
-		mutex_lock(&dev->struct_mutex);
-		i915_gem_track_fb(intel_fb_obj(plane->base.fb), NULL,
-				  plane->frontbuffer_bit);
-		mutex_unlock(&dev->struct_mutex);
-	}
-
-	if (atomic->wait_for_flips)
-		intel_crtc_wait_for_pending_flips(&crtc->base);
 
 	if (atomic->disable_fbc)
 		intel_fbc_disable_crtc(crtc);
@@ -4900,6 +4874,9 @@
 		return;
 
 	if (intel_crtc->config->has_pch_encoder)
+		intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
+
+	if (intel_crtc->config->has_pch_encoder)
 		intel_prepare_shared_dpll(intel_crtc);
 
 	if (intel_crtc->config->has_dp_encoder)
@@ -4917,7 +4894,6 @@
 	intel_crtc->active = true;
 
 	intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
-	intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
 
 	for_each_encoder_on_crtc(dev, crtc, encoder)
 		if (encoder->pre_enable)
@@ -4955,6 +4931,11 @@
 
 	if (HAS_PCH_CPT(dev))
 		cpt_verify_modeset(dev, intel_crtc->pipe);
+
+	/* Must wait for vblank to avoid spurious PCH FIFO underruns */
+	if (intel_crtc->config->has_pch_encoder)
+		intel_wait_for_vblank(dev, pipe);
+	intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
 }
 
 /* IPS only exists on ULT machines and is tied to pipe A. */
@@ -4977,6 +4958,10 @@
 	if (WARN_ON(intel_crtc->active))
 		return;
 
+	if (intel_crtc->config->has_pch_encoder)
+		intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
+						      false);
+
 	if (intel_crtc_to_shared_dpll(intel_crtc))
 		intel_enable_shared_dpll(intel_crtc);
 
@@ -5009,11 +4994,8 @@
 			encoder->pre_enable(encoder);
 	}
 
-	if (intel_crtc->config->has_pch_encoder) {
-		intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
-						      true);
+	if (intel_crtc->config->has_pch_encoder)
 		dev_priv->display.fdi_link_train(crtc);
-	}
 
 	if (!is_dsi)
 		intel_ddi_enable_pipe_clock(intel_crtc);
@@ -5050,6 +5032,10 @@
 		intel_opregion_notify_encoder(encoder, true);
 	}
 
+	if (intel_crtc->config->has_pch_encoder)
+		intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
+						      true);
+
 	/* If we change the relative order between pipe/planes enabling, we need
 	 * to change the workaround. */
 	hsw_workaround_pipe = pipe_config->hsw_workaround_pipe;
@@ -5081,7 +5067,9 @@
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct intel_encoder *encoder;
 	int pipe = intel_crtc->pipe;
-	u32 reg, temp;
+
+	if (intel_crtc->config->has_pch_encoder)
+		intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
 
 	for_each_encoder_on_crtc(dev, crtc, encoder)
 		encoder->disable(encoder);
@@ -5089,9 +5077,6 @@
 	drm_crtc_vblank_off(crtc);
 	assert_vblank_disabled(crtc);
 
-	if (intel_crtc->config->has_pch_encoder)
-		intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
-
 	intel_disable_pipe(intel_crtc);
 
 	ironlake_pfit_disable(intel_crtc, false);
@@ -5107,6 +5092,9 @@
 		ironlake_disable_pch_transcoder(dev_priv, pipe);
 
 		if (HAS_PCH_CPT(dev)) {
+			i915_reg_t reg;
+			u32 temp;
+
 			/* disable TRANS_DP_CTL */
 			reg = TRANS_DP_CTL(pipe);
 			temp = I915_READ(reg);
@@ -5123,6 +5111,8 @@
 
 		ironlake_fdi_pll_disable(intel_crtc);
 	}
+
+	intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
 }
 
 static void haswell_crtc_disable(struct drm_crtc *crtc)
@@ -5134,6 +5124,10 @@
 	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
 	bool is_dsi = intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI);
 
+	if (intel_crtc->config->has_pch_encoder)
+		intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
+						      false);
+
 	for_each_encoder_on_crtc(dev, crtc, encoder) {
 		intel_opregion_notify_encoder(encoder, false);
 		encoder->disable(encoder);
@@ -5142,9 +5136,6 @@
 	drm_crtc_vblank_off(crtc);
 	assert_vblank_disabled(crtc);
 
-	if (intel_crtc->config->has_pch_encoder)
-		intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
-						      false);
 	intel_disable_pipe(intel_crtc);
 
 	if (intel_crtc->config->dp_encoder_is_mst)
@@ -5169,6 +5160,10 @@
 	for_each_encoder_on_crtc(dev, crtc, encoder)
 		if (encoder->post_disable)
 			encoder->post_disable(encoder);
+
+	if (intel_crtc->config->has_pch_encoder)
+		intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
+						      true);
 }
 
 static void i9xx_pfit_enable(struct intel_crtc *crtc)
@@ -5199,15 +5194,15 @@
 {
 	switch (port) {
 	case PORT_A:
-		return POWER_DOMAIN_PORT_DDI_A_4_LANES;
+		return POWER_DOMAIN_PORT_DDI_A_LANES;
 	case PORT_B:
-		return POWER_DOMAIN_PORT_DDI_B_4_LANES;
+		return POWER_DOMAIN_PORT_DDI_B_LANES;
 	case PORT_C:
-		return POWER_DOMAIN_PORT_DDI_C_4_LANES;
+		return POWER_DOMAIN_PORT_DDI_C_LANES;
 	case PORT_D:
-		return POWER_DOMAIN_PORT_DDI_D_4_LANES;
+		return POWER_DOMAIN_PORT_DDI_D_LANES;
 	case PORT_E:
-		return POWER_DOMAIN_PORT_DDI_E_2_LANES;
+		return POWER_DOMAIN_PORT_DDI_E_LANES;
 	default:
 		MISSING_CASE(port);
 		return POWER_DOMAIN_PORT_OTHER;
@@ -5302,13 +5297,11 @@
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	enum pipe pipe = intel_crtc->pipe;
 	unsigned long mask;
-	enum transcoder transcoder;
+	enum transcoder transcoder = intel_crtc->config->cpu_transcoder;
 
 	if (!crtc->state->active)
 		return 0;
 
-	transcoder = intel_pipe_to_cpu_transcoder(dev->dev_private, pipe);
-
 	mask = BIT(POWER_DOMAIN_PIPE(pipe));
 	mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder));
 	if (intel_crtc->config->pch_pfit.enabled ||
@@ -5395,7 +5388,7 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (IS_SKYLAKE(dev)) {
+	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
 		u32 limit = I915_READ(SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK;
 
 		if (limit == SKL_DFSM_CDCLK_LIMIT_675)
@@ -5812,32 +5805,16 @@
 	if (I915_READ(DBUF_CTL) & DBUF_POWER_STATE)
 		DRM_ERROR("DBuf power disable timeout\n");
 
-	/*
-	 * DMC assumes ownership of LCPLL and will get confused if we touch it.
-	 */
-	if (dev_priv->csr.dmc_payload) {
-		/* disable DPLL0 */
-		I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) &
-					~LCPLL_PLL_ENABLE);
-		if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1))
-			DRM_ERROR("Couldn't disable DPLL0\n");
-	}
-
-	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+	/* disable DPLL0 */
+	I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) & ~LCPLL_PLL_ENABLE);
+	if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1))
+		DRM_ERROR("Couldn't disable DPLL0\n");
 }
 
 void skl_init_cdclk(struct drm_i915_private *dev_priv)
 {
-	u32 val;
 	unsigned int required_vco;
 
-	/* enable PCH reset handshake */
-	val = I915_READ(HSW_NDE_RSTWRN_OPT);
-	I915_WRITE(HSW_NDE_RSTWRN_OPT, val | RESET_PCH_HANDSHAKE_ENABLE);
-
-	/* enable PG1 and Misc I/O */
-	intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
-
 	/* DPLL0 not enabled (happens on early BIOS versions) */
 	if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) {
 		/* enable DPLL0 */
@@ -5858,6 +5835,45 @@
 		DRM_ERROR("DBuf power enable timeout\n");
 }
 
+int skl_sanitize_cdclk(struct drm_i915_private *dev_priv)
+{
+	uint32_t lcpll1 = I915_READ(LCPLL1_CTL);
+	uint32_t cdctl = I915_READ(CDCLK_CTL);
+	int freq = dev_priv->skl_boot_cdclk;
+
+	/*
+	 * check if the pre-os intialized the display
+	 * There is SWF18 scratchpad register defined which is set by the
+	 * pre-os which can be used by the OS drivers to check the status
+	 */
+	if ((I915_READ(SWF_ILK(0x18)) & 0x00FFFFFF) == 0)
+		goto sanitize;
+
+	/* Is PLL enabled and locked ? */
+	if (!((lcpll1 & LCPLL_PLL_ENABLE) && (lcpll1 & LCPLL_PLL_LOCK)))
+		goto sanitize;
+
+	/* DPLL okay; verify the cdclock
+	 *
+	 * Noticed in some instances that the freq selection is correct but
+	 * decimal part is programmed wrong from BIOS where pre-os does not
+	 * enable display. Verify the same as well.
+	 */
+	if (cdctl == ((cdctl & CDCLK_FREQ_SEL_MASK) | skl_cdclk_decimal(freq)))
+		/* All well; nothing to sanitize */
+		return false;
+sanitize:
+	/*
+	 * As of now initialize with max cdclk till
+	 * we get dynamic cdclk support
+	 * */
+	dev_priv->skl_boot_cdclk = dev_priv->max_cdclk_freq;
+	skl_init_cdclk(dev_priv);
+
+	/* we did have to sanitize */
+	return true;
+}
+
 /* Adjust CDclk dividers to allow high res or save power if possible */
 static void valleyview_set_cdclk(struct drm_device *dev, int cdclk)
 {
@@ -6322,7 +6338,8 @@
 		return;
 
 	if (to_intel_plane_state(crtc->primary->state)->visible) {
-		intel_crtc_wait_for_pending_flips(crtc);
+		WARN_ON(intel_crtc->unpin_work);
+
 		intel_pre_disable_primary(crtc);
 
 		intel_crtc_disable_planes(crtc, 1 << drm_plane_index(crtc->primary));
@@ -6642,6 +6659,15 @@
 		pipe_config_supports_ips(dev_priv, pipe_config);
 }
 
+static bool intel_crtc_supports_double_wide(const struct intel_crtc *crtc)
+{
+	const struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+
+	/* GDG double wide on either pipe, otherwise pipe A only */
+	return INTEL_INFO(dev_priv)->gen < 4 &&
+		(crtc->pipe == PIPE_A || IS_I915G(dev_priv));
+}
+
 static int intel_crtc_compute_config(struct intel_crtc *crtc,
 				     struct intel_crtc_state *pipe_config)
 {
@@ -6651,23 +6677,24 @@
 
 	/* FIXME should check pixel clock limits on all platforms */
 	if (INTEL_INFO(dev)->gen < 4) {
-		int clock_limit = dev_priv->max_cdclk_freq;
+		int clock_limit = dev_priv->max_cdclk_freq * 9 / 10;
 
 		/*
-		 * Enable pixel doubling when the dot clock
+		 * Enable double wide mode when the dot clock
 		 * is > 90% of the (display) core speed.
-		 *
-		 * GDG double wide on either pipe,
-		 * otherwise pipe A only.
 		 */
-		if ((crtc->pipe == PIPE_A || IS_I915G(dev)) &&
-		    adjusted_mode->crtc_clock > clock_limit * 9 / 10) {
+		if (intel_crtc_supports_double_wide(crtc) &&
+		    adjusted_mode->crtc_clock > clock_limit) {
 			clock_limit *= 2;
 			pipe_config->double_wide = true;
 		}
 
-		if (adjusted_mode->crtc_clock > clock_limit * 9 / 10)
+		if (adjusted_mode->crtc_clock > clock_limit) {
+			DRM_DEBUG_KMS("requested pixel clock (%d kHz) too high (max: %d kHz, double wide: %s)\n",
+				      adjusted_mode->crtc_clock, clock_limit,
+				      yesno(pipe_config->double_wide));
 			return -EINVAL;
+		}
 	}
 
 	/*
@@ -7432,7 +7459,7 @@
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int pipe = crtc->pipe;
-	int dpll_reg = DPLL(crtc->pipe);
+	i915_reg_t dpll_reg = DPLL(crtc->pipe);
 	enum dpio_channel port = vlv_pipe_to_channel(pipe);
 	u32 loopfilter, tribuf_calcntr;
 	u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac;
@@ -9350,8 +9377,8 @@
 
 	I915_STATE_WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n");
 	I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n");
-	I915_STATE_WARN(I915_READ(WRPLL_CTL1) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
-	I915_STATE_WARN(I915_READ(WRPLL_CTL2) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
+	I915_STATE_WARN(I915_READ(WRPLL_CTL(0)) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
+	I915_STATE_WARN(I915_READ(WRPLL_CTL(1)) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
 	I915_STATE_WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n");
 	I915_STATE_WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
 	     "CPU PWM1 enabled\n");
@@ -9813,7 +9840,7 @@
 
 	port = (tmp & TRANS_DDI_PORT_MASK) >> TRANS_DDI_PORT_SHIFT;
 
-	if (IS_SKYLAKE(dev))
+	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
 		skylake_get_ddi_pll(dev_priv, port, pipe_config);
 	else if (IS_BROXTON(dev))
 		bxt_get_ddi_pll(dev_priv, port, pipe_config);
@@ -10154,20 +10181,17 @@
 	int ret;
 
 	intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
-	if (!intel_fb) {
-		drm_gem_object_unreference(&obj->base);
+	if (!intel_fb)
 		return ERR_PTR(-ENOMEM);
-	}
 
 	ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj);
 	if (ret)
 		goto err;
 
 	return &intel_fb->base;
-err:
-	drm_gem_object_unreference(&obj->base);
-	kfree(intel_fb);
 
+err:
+	kfree(intel_fb);
 	return ERR_PTR(ret);
 }
 
@@ -10207,6 +10231,7 @@
 				  struct drm_display_mode *mode,
 				  int depth, int bpp)
 {
+	struct drm_framebuffer *fb;
 	struct drm_i915_gem_object *obj;
 	struct drm_mode_fb_cmd2 mode_cmd = { 0 };
 
@@ -10221,7 +10246,11 @@
 								bpp);
 	mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth);
 
-	return intel_framebuffer_create(dev, &mode_cmd, obj);
+	fb = intel_framebuffer_create(dev, &mode_cmd, obj);
+	if (IS_ERR(fb))
+		drm_gem_object_unreference_unlocked(&obj->base);
+
+	return fb;
 }
 
 static struct drm_framebuffer *
@@ -11124,7 +11153,7 @@
 	 */
 	if (ring->id == RCS) {
 		intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
-		intel_ring_emit(ring, DERRMR);
+		intel_ring_emit_reg(ring, DERRMR);
 		intel_ring_emit(ring, ~(DERRMR_PIPEA_PRI_FLIP_DONE |
 					DERRMR_PIPEB_PRI_FLIP_DONE |
 					DERRMR_PIPEC_PRI_FLIP_DONE));
@@ -11134,7 +11163,7 @@
 		else
 			intel_ring_emit(ring, MI_STORE_REGISTER_MEM |
 					      MI_SRM_LRM_GLOBAL_GTT);
-		intel_ring_emit(ring, DERRMR);
+		intel_ring_emit_reg(ring, DERRMR);
 		intel_ring_emit(ring, ring->scratch.gtt_offset + 256);
 		if (IS_GEN8(dev)) {
 			intel_ring_emit(ring, 0);
@@ -11179,13 +11208,14 @@
 }
 
 static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
+			     unsigned int rotation,
 			     struct intel_unpin_work *work)
 {
 	struct drm_device *dev = intel_crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_framebuffer *fb = intel_crtc->base.primary->fb;
 	const enum pipe pipe = intel_crtc->pipe;
-	u32 ctl, stride;
+	u32 ctl, stride, tile_height;
 
 	ctl = I915_READ(PLANE_CTL(pipe, 0));
 	ctl &= ~PLANE_CTL_TILED_MASK;
@@ -11209,9 +11239,16 @@
 	 * The stride is either expressed as a multiple of 64 bytes chunks for
 	 * linear buffers or in number of tiles for tiled buffers.
 	 */
-	stride = fb->pitches[0] /
-		 intel_fb_stride_alignment(dev, fb->modifier[0],
-					   fb->pixel_format);
+	if (intel_rotation_90_or_270(rotation)) {
+		/* stride = Surface height in tiles */
+		tile_height = intel_tile_height(dev, fb->pixel_format,
+						fb->modifier[0], 0);
+		stride = DIV_ROUND_UP(fb->height, tile_height);
+	} else {
+		stride = fb->pitches[0] /
+				intel_fb_stride_alignment(dev, fb->modifier[0],
+							  fb->pixel_format);
+	}
 
 	/*
 	 * Both PLANE_CTL and PLANE_STRIDE are not updated on vblank but on
@@ -11232,10 +11269,9 @@
 	struct intel_framebuffer *intel_fb =
 		to_intel_framebuffer(intel_crtc->base.primary->fb);
 	struct drm_i915_gem_object *obj = intel_fb->obj;
+	i915_reg_t reg = DSPCNTR(intel_crtc->plane);
 	u32 dspcntr;
-	u32 reg;
 
-	reg = DSPCNTR(intel_crtc->plane);
 	dspcntr = I915_READ(reg);
 
 	if (obj->tiling_mode != I915_TILING_NONE)
@@ -11269,7 +11305,7 @@
 	intel_pipe_update_start(crtc);
 
 	if (INTEL_INFO(mmio_flip->i915)->gen >= 9)
-		skl_do_mmio_flip(crtc, work);
+		skl_do_mmio_flip(crtc, mmio_flip->rotation, work);
 	else
 		/* use_mmio_flip() retricts MMIO flips to ilk+ */
 		ilk_do_mmio_flip(crtc, work);
@@ -11296,10 +11332,7 @@
 
 static int intel_queue_mmio_flip(struct drm_device *dev,
 				 struct drm_crtc *crtc,
-				 struct drm_framebuffer *fb,
-				 struct drm_i915_gem_object *obj,
-				 struct intel_engine_cs *ring,
-				 uint32_t flags)
+				 struct drm_i915_gem_object *obj)
 {
 	struct intel_mmio_flip *mmio_flip;
 
@@ -11310,6 +11343,7 @@
 	mmio_flip->i915 = to_i915(dev);
 	mmio_flip->req = i915_gem_request_reference(obj->last_write_req);
 	mmio_flip->crtc = to_intel_crtc(crtc);
+	mmio_flip->rotation = crtc->primary->state->rotation;
 
 	INIT_WORK(&mmio_flip->work, intel_mmio_flip_work_func);
 	schedule_work(&mmio_flip->work);
@@ -11515,9 +11549,14 @@
 	 * synchronisation, so all we want here is to pin the framebuffer
 	 * into the display plane and skip any waits.
 	 */
+	if (!mmio_flip) {
+		ret = i915_gem_object_sync(obj, ring, &request);
+		if (ret)
+			goto cleanup_pending;
+	}
+
 	ret = intel_pin_and_fence_fb_obj(crtc->primary, fb,
-					 crtc->primary->state,
-					 mmio_flip ? i915_gem_request_get_ring(obj->last_write_req) : ring, &request);
+					 crtc->primary->state);
 	if (ret)
 		goto cleanup_pending;
 
@@ -11526,8 +11565,7 @@
 	work->gtt_offset += intel_crtc->dspaddr_offset;
 
 	if (mmio_flip) {
-		ret = intel_queue_mmio_flip(dev, crtc, fb, obj, ring,
-					    page_flip_flags);
+		ret = intel_queue_mmio_flip(dev, crtc, obj);
 		if (ret)
 			goto cleanup_unpin;
 
@@ -11641,18 +11679,32 @@
 static bool intel_wm_need_update(struct drm_plane *plane,
 				 struct drm_plane_state *state)
 {
-	/* Update watermarks on tiling changes. */
+	struct intel_plane_state *new = to_intel_plane_state(state);
+	struct intel_plane_state *cur = to_intel_plane_state(plane->state);
+
+	/* Update watermarks on tiling or size changes. */
 	if (!plane->state->fb || !state->fb ||
 	    plane->state->fb->modifier[0] != state->fb->modifier[0] ||
-	    plane->state->rotation != state->rotation)
-		return true;
-
-	if (plane->state->crtc_w != state->crtc_w)
+	    plane->state->rotation != state->rotation ||
+	    drm_rect_width(&new->src) != drm_rect_width(&cur->src) ||
+	    drm_rect_height(&new->src) != drm_rect_height(&cur->src) ||
+	    drm_rect_width(&new->dst) != drm_rect_width(&cur->dst) ||
+	    drm_rect_height(&new->dst) != drm_rect_height(&cur->dst))
 		return true;
 
 	return false;
 }
 
+static bool needs_scaling(struct intel_plane_state *state)
+{
+	int src_w = drm_rect_width(&state->src) >> 16;
+	int src_h = drm_rect_height(&state->src) >> 16;
+	int dst_w = drm_rect_width(&state->dst);
+	int dst_h = drm_rect_height(&state->dst);
+
+	return (src_w != dst_w || src_h != dst_h);
+}
+
 int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
 				    struct drm_plane_state *plane_state)
 {
@@ -11668,7 +11720,6 @@
 	bool mode_changed = needs_modeset(crtc_state);
 	bool was_crtc_enabled = crtc->state->active;
 	bool is_crtc_enabled = crtc_state->active;
-
 	bool turn_off, turn_on, visible, was_visible;
 	struct drm_framebuffer *fb = plane_state->fb;
 
@@ -11681,14 +11732,6 @@
 			return ret;
 	}
 
-	/*
-	 * Disabling a plane is always okay; we just need to update
-	 * fb tracking in a special way since cleanup_fb() won't
-	 * get called by the plane helpers.
-	 */
-	if (old_plane_state->base.fb && !fb)
-		intel_crtc->atomic.disabled_planes |= 1 << i;
-
 	was_visible = old_plane_state->visible;
 	visible = to_intel_plane_state(plane_state)->visible;
 
@@ -11738,7 +11781,6 @@
 
 	switch (plane->type) {
 	case DRM_PLANE_TYPE_PRIMARY:
-		intel_crtc->atomic.wait_for_flips = true;
 		intel_crtc->atomic.pre_disable_primary = turn_off;
 		intel_crtc->atomic.post_enable_primary = turn_on;
 
@@ -11786,11 +11828,23 @@
 	case DRM_PLANE_TYPE_CURSOR:
 		break;
 	case DRM_PLANE_TYPE_OVERLAY:
-		if (turn_off && !mode_changed) {
+		/*
+		 * WaCxSRDisabledForSpriteScaling:ivb
+		 *
+		 * cstate->update_wm was already set above, so this flag will
+		 * take effect when we commit and program watermarks.
+		 */
+		if (IS_IVYBRIDGE(dev) &&
+		    needs_scaling(to_intel_plane_state(plane_state)) &&
+		    !needs_scaling(old_plane_state)) {
+			to_intel_crtc_state(crtc_state)->disable_lp_wm = true;
+		} else if (turn_off && !mode_changed) {
 			intel_crtc->atomic.wait_vblank = true;
 			intel_crtc->atomic.update_sprite_watermarks |=
 				1 << i;
 		}
+
+		break;
 	}
 	return 0;
 }
@@ -11875,6 +11929,12 @@
 	}
 
 	ret = 0;
+	if (dev_priv->display.compute_pipe_wm) {
+		ret = dev_priv->display.compute_pipe_wm(intel_crtc, state);
+		if (ret)
+			return ret;
+	}
+
 	if (INTEL_INFO(dev)->gen >= 9) {
 		if (mode_changed)
 			ret = skl_update_scaler_crtc(pipe_config);
@@ -12064,7 +12124,7 @@
 			      pipe_config->dpll_hw_state.pll9,
 			      pipe_config->dpll_hw_state.pll10,
 			      pipe_config->dpll_hw_state.pcsdw12);
-	} else if (IS_SKYLAKE(dev)) {
+	} else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
 		DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: "
 			      "ctrl1: 0x%x, cfgcr1: 0x%x, cfgcr2: 0x%x\n",
 			      pipe_config->ddi_pll_sel,
@@ -12322,6 +12382,18 @@
 			crtc->hwmode = crtc->state->adjusted_mode;
 		else
 			crtc->hwmode.crtc_clock = 0;
+
+		/*
+		 * Update legacy state to satisfy fbc code. This can
+		 * be removed when fbc uses the atomic state.
+		 */
+		if (drm_atomic_get_existing_plane_state(state, crtc->primary)) {
+			struct drm_plane_state *plane_state = crtc->primary->state;
+
+			crtc->primary->fb = plane_state->fb;
+			crtc->x = plane_state->src_x >> 16;
+			crtc->y = plane_state->src_y >> 16;
+		}
 	}
 }
 
@@ -12347,7 +12419,7 @@
 	list_for_each_entry((intel_crtc), \
 			    &(dev)->mode_config.crtc_list, \
 			    base.head) \
-		if (mask & (1 <<(intel_crtc)->pipe))
+		for_each_if (mask & (1 <<(intel_crtc)->pipe))
 
 static bool
 intel_compare_m_n(unsigned int m, unsigned int n,
@@ -13085,6 +13157,45 @@
 	return 0;
 }
 
+/*
+ * Handle calculation of various watermark data at the end of the atomic check
+ * phase.  The code here should be run after the per-crtc and per-plane 'check'
+ * handlers to ensure that all derived state has been updated.
+ */
+static void calc_watermark_data(struct drm_atomic_state *state)
+{
+	struct drm_device *dev = state->dev;
+	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *cstate;
+	struct drm_plane *plane;
+	struct drm_plane_state *pstate;
+
+	/*
+	 * Calculate watermark configuration details now that derived
+	 * plane/crtc state is all properly updated.
+	 */
+	drm_for_each_crtc(crtc, dev) {
+		cstate = drm_atomic_get_existing_crtc_state(state, crtc) ?:
+			crtc->state;
+
+		if (cstate->active)
+			intel_state->wm_config.num_pipes_active++;
+	}
+	drm_for_each_legacy_plane(plane, dev) {
+		pstate = drm_atomic_get_existing_plane_state(state, plane) ?:
+			plane->state;
+
+		if (!to_intel_plane_state(pstate)->visible)
+			continue;
+
+		intel_state->wm_config.sprites_enabled = true;
+		if (pstate->crtc_w != pstate->src_w >> 16 ||
+		    pstate->crtc_h != pstate->src_h >> 16)
+			intel_state->wm_config.sprites_scaled = true;
+	}
+}
+
 /**
  * intel_atomic_check - validate state object
  * @dev: drm device
@@ -13093,6 +13204,7 @@
 static int intel_atomic_check(struct drm_device *dev,
 			      struct drm_atomic_state *state)
 {
+	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
 	struct drm_crtc *crtc;
 	struct drm_crtc_state *crtc_state;
 	int ret, i;
@@ -13160,10 +13272,81 @@
 		if (ret)
 			return ret;
 	} else
-		to_intel_atomic_state(state)->cdclk =
-			to_i915(state->dev)->cdclk_freq;
+		intel_state->cdclk = to_i915(state->dev)->cdclk_freq;
 
-	return drm_atomic_helper_check_planes(state->dev, state);
+	ret = drm_atomic_helper_check_planes(state->dev, state);
+	if (ret)
+		return ret;
+
+	calc_watermark_data(state);
+
+	return 0;
+}
+
+static int intel_atomic_prepare_commit(struct drm_device *dev,
+				       struct drm_atomic_state *state,
+				       bool async)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_plane_state *plane_state;
+	struct drm_crtc_state *crtc_state;
+	struct drm_plane *plane;
+	struct drm_crtc *crtc;
+	int i, ret;
+
+	if (async) {
+		DRM_DEBUG_KMS("i915 does not yet support async commit\n");
+		return -EINVAL;
+	}
+
+	for_each_crtc_in_state(state, crtc, crtc_state, i) {
+		ret = intel_crtc_wait_for_pending_flips(crtc);
+		if (ret)
+			return ret;
+
+		if (atomic_read(&to_intel_crtc(crtc)->unpin_work_count) >= 2)
+			flush_workqueue(dev_priv->wq);
+	}
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
+
+	ret = drm_atomic_helper_prepare_planes(dev, state);
+	if (!ret && !async && !i915_reset_in_progress(&dev_priv->gpu_error)) {
+		u32 reset_counter;
+
+		reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
+		mutex_unlock(&dev->struct_mutex);
+
+		for_each_plane_in_state(state, plane, plane_state, i) {
+			struct intel_plane_state *intel_plane_state =
+				to_intel_plane_state(plane_state);
+
+			if (!intel_plane_state->wait_req)
+				continue;
+
+			ret = __i915_wait_request(intel_plane_state->wait_req,
+						  reset_counter, true,
+						  NULL, NULL);
+
+			/* Swallow -EIO errors to allow updates during hw lockup. */
+			if (ret == -EIO)
+				ret = 0;
+
+			if (ret)
+				break;
+		}
+
+		if (!ret)
+			return 0;
+
+		mutex_lock(&dev->struct_mutex);
+		drm_atomic_helper_cleanup_planes(dev, state);
+	}
+
+	mutex_unlock(&dev->struct_mutex);
+	return ret;
 }
 
 /**
@@ -13187,22 +13370,20 @@
 			       bool async)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_crtc *crtc;
 	struct drm_crtc_state *crtc_state;
+	struct drm_crtc *crtc;
 	int ret = 0;
 	int i;
 	bool any_ms = false;
 
-	if (async) {
-		DRM_DEBUG_KMS("i915 does not yet support async commit\n");
-		return -EINVAL;
+	ret = intel_atomic_prepare_commit(dev, state, async);
+	if (ret) {
+		DRM_DEBUG_ATOMIC("Preparing state failed with %i\n", ret);
+		return ret;
 	}
 
-	ret = drm_atomic_helper_prepare_planes(dev, state);
-	if (ret)
-		return ret;
-
 	drm_atomic_helper_swap_state(dev, state);
+	dev_priv->wm.config = to_intel_atomic_state(state)->wm_config;
 
 	for_each_crtc_in_state(state, crtc, crtc_state, i) {
 		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -13240,6 +13421,9 @@
 			to_intel_crtc_state(crtc->state)->update_pipe;
 		unsigned long put_domains = 0;
 
+		if (modeset)
+			intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
+
 		if (modeset && crtc->state->active) {
 			update_scanline_offset(to_intel_crtc(crtc));
 			dev_priv->display.crtc_enable(crtc);
@@ -13255,18 +13439,26 @@
 		if (!modeset)
 			intel_pre_plane_update(intel_crtc);
 
-		drm_atomic_helper_commit_planes_on_crtc(crtc_state);
+		if (crtc->state->active &&
+		    (crtc->state->planes_changed || update_pipe))
+			drm_atomic_helper_commit_planes_on_crtc(crtc_state);
 
 		if (put_domains)
 			modeset_put_power_domains(dev_priv, put_domains);
 
 		intel_post_plane_update(intel_crtc);
+
+		if (modeset)
+			intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
 	}
 
 	/* FIXME: add subpixel order */
 
 	drm_atomic_helper_wait_for_vblanks(dev, state);
+
+	mutex_lock(&dev->struct_mutex);
 	drm_atomic_helper_cleanup_planes(dev, state);
+	mutex_unlock(&dev->struct_mutex);
 
 	if (any_ms)
 		intel_modeset_check_state(dev, state);
@@ -13435,6 +13627,8 @@
  * bits.  Some older platforms need special physical address handling for
  * cursor planes.
  *
+ * Must be called with struct_mutex held.
+ *
  * Returns 0 on success, negative error code on failure.
  */
 int
@@ -13445,28 +13639,58 @@
 	struct drm_framebuffer *fb = new_state->fb;
 	struct intel_plane *intel_plane = to_intel_plane(plane);
 	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-	struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
+	struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->state->fb);
 	int ret = 0;
 
-	if (!obj)
+	if (!obj && !old_obj)
 		return 0;
 
-	mutex_lock(&dev->struct_mutex);
+	if (old_obj) {
+		struct drm_crtc_state *crtc_state =
+			drm_atomic_get_existing_crtc_state(new_state->state, plane->state->crtc);
 
-	if (plane->type == DRM_PLANE_TYPE_CURSOR &&
+		/* Big Hammer, we also need to ensure that any pending
+		 * MI_WAIT_FOR_EVENT inside a user batch buffer on the
+		 * current scanout is retired before unpinning the old
+		 * framebuffer. Note that we rely on userspace rendering
+		 * into the buffer attached to the pipe they are waiting
+		 * on. If not, userspace generates a GPU hang with IPEHR
+		 * point to the MI_WAIT_FOR_EVENT.
+		 *
+		 * This should only fail upon a hung GPU, in which case we
+		 * can safely continue.
+		 */
+		if (needs_modeset(crtc_state))
+			ret = i915_gem_object_wait_rendering(old_obj, true);
+
+		/* Swallow -EIO errors to allow updates during hw lockup. */
+		if (ret && ret != -EIO)
+			return ret;
+	}
+
+	if (!obj) {
+		ret = 0;
+	} else if (plane->type == DRM_PLANE_TYPE_CURSOR &&
 	    INTEL_INFO(dev)->cursor_needs_physical) {
 		int align = IS_I830(dev) ? 16 * 1024 : 256;
 		ret = i915_gem_object_attach_phys(obj, align);
 		if (ret)
 			DRM_DEBUG_KMS("failed to attach phys object\n");
 	} else {
-		ret = intel_pin_and_fence_fb_obj(plane, fb, new_state, NULL, NULL);
+		ret = intel_pin_and_fence_fb_obj(plane, fb, new_state);
 	}
 
-	if (ret == 0)
-		i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
+	if (ret == 0) {
+		if (obj) {
+			struct intel_plane_state *plane_state =
+				to_intel_plane_state(new_state);
 
-	mutex_unlock(&dev->struct_mutex);
+			i915_gem_request_assign(&plane_state->wait_req,
+						obj->last_write_req);
+		}
+
+		i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
+	}
 
 	return ret;
 }
@@ -13477,23 +13701,35 @@
  * @fb: old framebuffer that was on plane
  *
  * Cleans up a framebuffer that has just been removed from a plane.
+ *
+ * Must be called with struct_mutex held.
  */
 void
 intel_cleanup_plane_fb(struct drm_plane *plane,
 		       const struct drm_plane_state *old_state)
 {
 	struct drm_device *dev = plane->dev;
-	struct drm_i915_gem_object *obj = intel_fb_obj(old_state->fb);
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct intel_plane_state *old_intel_state;
+	struct drm_i915_gem_object *old_obj = intel_fb_obj(old_state->fb);
+	struct drm_i915_gem_object *obj = intel_fb_obj(plane->state->fb);
 
-	if (!obj)
+	old_intel_state = to_intel_plane_state(old_state);
+
+	if (!obj && !old_obj)
 		return;
 
-	if (plane->type != DRM_PLANE_TYPE_CURSOR ||
-	    !INTEL_INFO(dev)->cursor_needs_physical) {
-		mutex_lock(&dev->struct_mutex);
+	if (old_obj && (plane->type != DRM_PLANE_TYPE_CURSOR ||
+	    !INTEL_INFO(dev)->cursor_needs_physical))
 		intel_unpin_fb_obj(old_state->fb, old_state);
-		mutex_unlock(&dev->struct_mutex);
-	}
+
+	/* prepare_fb aborted? */
+	if ((old_obj && (old_obj->frontbuffer_bits & intel_plane->frontbuffer_bit)) ||
+	    (obj && !(obj->frontbuffer_bits & intel_plane->frontbuffer_bit)))
+		i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
+
+	i915_gem_request_assign(&old_intel_state->wait_req, NULL);
+
 }
 
 int
@@ -13512,7 +13748,7 @@
 	crtc_clock = crtc_state->base.adjusted_mode.crtc_clock;
 	cdclk = to_intel_atomic_state(crtc_state->base.state)->cdclk;
 
-	if (!crtc_clock || !cdclk)
+	if (WARN_ON_ONCE(!crtc_clock || cdclk < crtc_clock))
 		return DRM_PLANE_HELPER_NO_SCALING;
 
 	/*
@@ -13560,18 +13796,8 @@
 	struct drm_framebuffer *fb = state->base.fb;
 	struct drm_device *dev = plane->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc;
-	struct drm_rect *src = &state->src;
 
 	crtc = crtc ? crtc : plane->crtc;
-	intel_crtc = to_intel_crtc(crtc);
-
-	plane->fb = fb;
-	crtc->x = src->x1 >> 16;
-	crtc->y = src->y1 >> 16;
-
-	if (!crtc->state->active)
-		return;
 
 	dev_priv->display.update_primary_plane(crtc, fb,
 					       state->src.x1 >> 16,
@@ -13601,8 +13827,7 @@
 		intel_update_watermarks(crtc);
 
 	/* Perform vblank evasion around commit operation */
-	if (crtc->state->active)
-		intel_pipe_update_start(intel_crtc);
+	intel_pipe_update_start(intel_crtc);
 
 	if (modeset)
 		return;
@@ -13618,8 +13843,7 @@
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-	if (crtc->state->active)
-		intel_pipe_update_end(intel_crtc);
+	intel_pipe_update_end(intel_crtc);
 }
 
 /**
@@ -14087,7 +14311,7 @@
 		 */
 		found = I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_INIT_DISPLAY_DETECTED;
 		/* WaIgnoreDDIAStrap: skl */
-		if (found || IS_SKYLAKE(dev))
+		if (found || IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
 			intel_ddi_init(dev, PORT_A);
 
 		/* DDI B, C and D detection is indicated by the SFUSE_STRAP
@@ -14103,7 +14327,7 @@
 		/*
 		 * On SKL we don't have a way to detect DDI-E so we rely on VBT.
 		 */
-		if (IS_SKYLAKE(dev) &&
+		if ((IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) &&
 		    (dev_priv->vbt.ddi_port_info[PORT_E].supports_dp ||
 		     dev_priv->vbt.ddi_port_info[PORT_E].supports_dvi ||
 		     dev_priv->vbt.ddi_port_info[PORT_E].supports_hdmi))
@@ -14118,7 +14342,7 @@
 
 		if (I915_READ(PCH_HDMIB) & SDVO_DETECTED) {
 			/* PCH SDVOB multiplex with HDMIB */
-			found = intel_sdvo_init(dev, PCH_SDVOB, true);
+			found = intel_sdvo_init(dev, PCH_SDVOB, PORT_B);
 			if (!found)
 				intel_hdmi_init(dev, PCH_HDMIB, PORT_B);
 			if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
@@ -14174,7 +14398,7 @@
 
 		if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) {
 			DRM_DEBUG_KMS("probing SDVOB\n");
-			found = intel_sdvo_init(dev, GEN3_SDVOB, true);
+			found = intel_sdvo_init(dev, GEN3_SDVOB, PORT_B);
 			if (!found && IS_G4X(dev)) {
 				DRM_DEBUG_KMS("probing HDMI on SDVOB\n");
 				intel_hdmi_init(dev, GEN4_HDMIB, PORT_B);
@@ -14188,7 +14412,7 @@
 
 		if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) {
 			DRM_DEBUG_KMS("probing SDVOC\n");
-			found = intel_sdvo_init(dev, GEN3_SDVOC, false);
+			found = intel_sdvo_init(dev, GEN3_SDVOC, PORT_C);
 		}
 
 		if (!found && (I915_READ(GEN3_SDVOC) & SDVO_DETECTED)) {
@@ -14454,8 +14678,9 @@
 static struct drm_framebuffer *
 intel_user_framebuffer_create(struct drm_device *dev,
 			      struct drm_file *filp,
-			      struct drm_mode_fb_cmd2 *user_mode_cmd)
+			      const struct drm_mode_fb_cmd2 *user_mode_cmd)
 {
+	struct drm_framebuffer *fb;
 	struct drm_i915_gem_object *obj;
 	struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd;
 
@@ -14464,7 +14689,11 @@
 	if (&obj->base == NULL)
 		return ERR_PTR(-ENOENT);
 
-	return intel_framebuffer_create(dev, &mode_cmd, obj);
+	fb = intel_framebuffer_create(dev, &mode_cmd, obj);
+	if (IS_ERR(fb))
+		drm_gem_object_unreference_unlocked(&obj->base);
+
+	return fb;
 }
 
 #ifndef CONFIG_DRM_FBDEV_EMULATION
@@ -14549,7 +14778,7 @@
 	}
 
 	/* Returns the core display clock speed */
-	if (IS_SKYLAKE(dev))
+	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
 		dev_priv->display.get_display_clock_speed =
 			skylake_get_display_clock_speed;
 	else if (IS_BROXTON(dev))
@@ -14838,7 +15067,7 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u8 sr1;
-	u32 vga_reg = i915_vgacntrl_reg(dev);
+	i915_reg_t vga_reg = i915_vgacntrl_reg(dev);
 
 	/* WaEnableVGAAccessThroughIOPort:ctg,elk,ilk,snb,ivb,vlv,hsw */
 	vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
@@ -14954,9 +15183,6 @@
 	i915_disable_vga(dev);
 	intel_setup_outputs(dev);
 
-	/* Just in case the BIOS is doing something questionable. */
-	intel_fbc_disable(dev_priv);
-
 	drm_modeset_lock_all(dev);
 	intel_modeset_setup_hw_state(dev);
 	drm_modeset_unlock_all(dev);
@@ -15043,10 +15269,9 @@
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 reg;
+	i915_reg_t reg = PIPECONF(crtc->config->cpu_transcoder);
 
 	/* Clear any frame start delays used for debugging left by the BIOS */
-	reg = PIPECONF(crtc->config->cpu_transcoder);
 	I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
 
 	/* restore vblank interrupts to correct state */
@@ -15200,7 +15425,7 @@
 void i915_redisable_vga_power_on(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 vga_reg = i915_vgacntrl_reg(dev);
+	i915_reg_t vga_reg = i915_vgacntrl_reg(dev);
 
 	if (!(I915_READ(vga_reg) & VGA_DISP_DISABLE)) {
 		DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n");
@@ -15239,7 +15464,7 @@
 	struct intel_plane_state *plane_state =
 		to_intel_plane_state(primary->state);
 
-	plane_state->visible =
+	plane_state->visible = crtc->active &&
 		primary_get_hw_state(to_intel_plane(primary));
 
 	if (plane_state->visible)
@@ -15496,8 +15721,7 @@
 		mutex_lock(&dev->struct_mutex);
 		ret = intel_pin_and_fence_fb_obj(c->primary,
 						 c->primary->fb,
-						 c->primary->state,
-						 NULL, NULL);
+						 c->primary->state);
 		mutex_unlock(&dev->struct_mutex);
 		if (ret) {
 			DRM_ERROR("failed to pin boot fb on pipe %d\n",
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 78b8ec8..e1456ea 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -541,7 +541,8 @@
 	}
 }
 
-static u32 _pp_ctrl_reg(struct intel_dp *intel_dp)
+static i915_reg_t
+_pp_ctrl_reg(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 
@@ -553,7 +554,8 @@
 		return VLV_PIPE_PP_CONTROL(vlv_power_sequencer_pipe(intel_dp));
 }
 
-static u32 _pp_stat_reg(struct intel_dp *intel_dp)
+static i915_reg_t
+_pp_stat_reg(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 
@@ -582,7 +584,7 @@
 
 	if (IS_VALLEYVIEW(dev)) {
 		enum pipe pipe = vlv_power_sequencer_pipe(intel_dp);
-		u32 pp_ctrl_reg, pp_div_reg;
+		i915_reg_t pp_ctrl_reg, pp_div_reg;
 		u32 pp_div;
 
 		pp_ctrl_reg = VLV_PIPE_PP_CONTROL(pipe);
@@ -652,7 +654,7 @@
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 	struct drm_device *dev = intel_dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg;
+	i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg;
 	uint32_t status;
 	bool done;
 
@@ -750,7 +752,7 @@
 	else
 		precharge = 5;
 
-	if (IS_BROADWELL(dev) && intel_dp->aux_ch_ctl_reg == DPA_AUX_CH_CTL)
+	if (IS_BROADWELL(dev) && intel_dig_port->port == PORT_A)
 		timeout = DP_AUX_CH_CTL_TIME_OUT_600us;
 	else
 		timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
@@ -789,8 +791,7 @@
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 	struct drm_device *dev = intel_dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg;
-	uint32_t ch_data = ch_ctl + 4;
+	i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg;
 	uint32_t aux_clock_divider;
 	int i, ret, recv_bytes;
 	uint32_t status;
@@ -854,7 +855,7 @@
 		for (try = 0; try < 5; try++) {
 			/* Load the send data into the aux channel data registers */
 			for (i = 0; i < send_bytes; i += 4)
-				I915_WRITE(ch_data + i,
+				I915_WRITE(intel_dp->aux_ch_data_reg[i >> 2],
 					   intel_dp_pack_aux(send + i,
 							     send_bytes - i));
 
@@ -918,7 +919,7 @@
 		recv_bytes = recv_size;
 
 	for (i = 0; i < recv_bytes; i += 4)
-		intel_dp_unpack_aux(I915_READ(ch_data + i),
+		intel_dp_unpack_aux(I915_READ(intel_dp->aux_ch_data_reg[i >> 2]),
 				    recv + i, recv_bytes - i);
 
 	ret = recv_bytes;
@@ -1005,96 +1006,206 @@
 	return ret;
 }
 
-static void
-intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
+static i915_reg_t g4x_aux_ctl_reg(struct drm_i915_private *dev_priv,
+				       enum port port)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-	enum port port = intel_dig_port->port;
-	struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port];
-	const char *name = NULL;
-	uint32_t porte_aux_ctl_reg = DPA_AUX_CH_CTL;
-	int ret;
-
-	/* On SKL we don't have Aux for port E so we rely on VBT to set
-	 * a proper alternate aux channel.
-	 */
-	if (IS_SKYLAKE(dev) && port == PORT_E) {
-		switch (info->alternate_aux_channel) {
-		case DP_AUX_B:
-			porte_aux_ctl_reg = DPB_AUX_CH_CTL;
-			break;
-		case DP_AUX_C:
-			porte_aux_ctl_reg = DPC_AUX_CH_CTL;
-			break;
-		case DP_AUX_D:
-			porte_aux_ctl_reg = DPD_AUX_CH_CTL;
-			break;
-		case DP_AUX_A:
-		default:
-			porte_aux_ctl_reg = DPA_AUX_CH_CTL;
-		}
+	switch (port) {
+	case PORT_B:
+	case PORT_C:
+	case PORT_D:
+		return DP_AUX_CH_CTL(port);
+	default:
+		MISSING_CASE(port);
+		return DP_AUX_CH_CTL(PORT_B);
 	}
+}
+
+static i915_reg_t g4x_aux_data_reg(struct drm_i915_private *dev_priv,
+					enum port port, int index)
+{
+	switch (port) {
+	case PORT_B:
+	case PORT_C:
+	case PORT_D:
+		return DP_AUX_CH_DATA(port, index);
+	default:
+		MISSING_CASE(port);
+		return DP_AUX_CH_DATA(PORT_B, index);
+	}
+}
+
+static i915_reg_t ilk_aux_ctl_reg(struct drm_i915_private *dev_priv,
+				       enum port port)
+{
+	switch (port) {
+	case PORT_A:
+		return DP_AUX_CH_CTL(port);
+	case PORT_B:
+	case PORT_C:
+	case PORT_D:
+		return PCH_DP_AUX_CH_CTL(port);
+	default:
+		MISSING_CASE(port);
+		return DP_AUX_CH_CTL(PORT_A);
+	}
+}
+
+static i915_reg_t ilk_aux_data_reg(struct drm_i915_private *dev_priv,
+					enum port port, int index)
+{
+	switch (port) {
+	case PORT_A:
+		return DP_AUX_CH_DATA(port, index);
+	case PORT_B:
+	case PORT_C:
+	case PORT_D:
+		return PCH_DP_AUX_CH_DATA(port, index);
+	default:
+		MISSING_CASE(port);
+		return DP_AUX_CH_DATA(PORT_A, index);
+	}
+}
+
+/*
+ * On SKL we don't have Aux for port E so we rely
+ * on VBT to set a proper alternate aux channel.
+ */
+static enum port skl_porte_aux_port(struct drm_i915_private *dev_priv)
+{
+	const struct ddi_vbt_port_info *info =
+		&dev_priv->vbt.ddi_port_info[PORT_E];
+
+	switch (info->alternate_aux_channel) {
+	case DP_AUX_A:
+		return PORT_A;
+	case DP_AUX_B:
+		return PORT_B;
+	case DP_AUX_C:
+		return PORT_C;
+	case DP_AUX_D:
+		return PORT_D;
+	default:
+		MISSING_CASE(info->alternate_aux_channel);
+		return PORT_A;
+	}
+}
+
+static i915_reg_t skl_aux_ctl_reg(struct drm_i915_private *dev_priv,
+				       enum port port)
+{
+	if (port == PORT_E)
+		port = skl_porte_aux_port(dev_priv);
 
 	switch (port) {
 	case PORT_A:
-		intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL;
-		name = "DPDDC-A";
-		break;
 	case PORT_B:
-		intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL;
-		name = "DPDDC-B";
-		break;
 	case PORT_C:
-		intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL;
-		name = "DPDDC-C";
-		break;
 	case PORT_D:
-		intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL;
-		name = "DPDDC-D";
-		break;
-	case PORT_E:
-		intel_dp->aux_ch_ctl_reg = porte_aux_ctl_reg;
-		name = "DPDDC-E";
-		break;
+		return DP_AUX_CH_CTL(port);
 	default:
-		BUG();
+		MISSING_CASE(port);
+		return DP_AUX_CH_CTL(PORT_A);
 	}
+}
 
-	/*
-	 * The AUX_CTL register is usually DP_CTL + 0x10.
-	 *
-	 * On Haswell and Broadwell though:
-	 *   - Both port A DDI_BUF_CTL and DDI_AUX_CTL are on the CPU
-	 *   - Port B/C/D AUX channels are on the PCH, DDI_BUF_CTL on the CPU
-	 *
-	 * Skylake moves AUX_CTL back next to DDI_BUF_CTL, on the CPU.
-	 */
-	if (!IS_HASWELL(dev) && !IS_BROADWELL(dev) && port != PORT_E)
-		intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10;
+static i915_reg_t skl_aux_data_reg(struct drm_i915_private *dev_priv,
+					enum port port, int index)
+{
+	if (port == PORT_E)
+		port = skl_porte_aux_port(dev_priv);
 
-	intel_dp->aux.name = name;
+	switch (port) {
+	case PORT_A:
+	case PORT_B:
+	case PORT_C:
+	case PORT_D:
+		return DP_AUX_CH_DATA(port, index);
+	default:
+		MISSING_CASE(port);
+		return DP_AUX_CH_DATA(PORT_A, index);
+	}
+}
+
+static i915_reg_t intel_aux_ctl_reg(struct drm_i915_private *dev_priv,
+					 enum port port)
+{
+	if (INTEL_INFO(dev_priv)->gen >= 9)
+		return skl_aux_ctl_reg(dev_priv, port);
+	else if (HAS_PCH_SPLIT(dev_priv))
+		return ilk_aux_ctl_reg(dev_priv, port);
+	else
+		return g4x_aux_ctl_reg(dev_priv, port);
+}
+
+static i915_reg_t intel_aux_data_reg(struct drm_i915_private *dev_priv,
+					  enum port port, int index)
+{
+	if (INTEL_INFO(dev_priv)->gen >= 9)
+		return skl_aux_data_reg(dev_priv, port, index);
+	else if (HAS_PCH_SPLIT(dev_priv))
+		return ilk_aux_data_reg(dev_priv, port, index);
+	else
+		return g4x_aux_data_reg(dev_priv, port, index);
+}
+
+static void intel_aux_reg_init(struct intel_dp *intel_dp)
+{
+	struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp));
+	enum port port = dp_to_dig_port(intel_dp)->port;
+	int i;
+
+	intel_dp->aux_ch_ctl_reg = intel_aux_ctl_reg(dev_priv, port);
+	for (i = 0; i < ARRAY_SIZE(intel_dp->aux_ch_data_reg); i++)
+		intel_dp->aux_ch_data_reg[i] = intel_aux_data_reg(dev_priv, port, i);
+}
+
+static void
+intel_dp_aux_fini(struct intel_dp *intel_dp)
+{
+	drm_dp_aux_unregister(&intel_dp->aux);
+	kfree(intel_dp->aux.name);
+}
+
+static int
+intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
+{
+	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	enum port port = intel_dig_port->port;
+	int ret;
+
+	intel_aux_reg_init(intel_dp);
+
+	intel_dp->aux.name = kasprintf(GFP_KERNEL, "DPDDC-%c", port_name(port));
+	if (!intel_dp->aux.name)
+		return -ENOMEM;
+
 	intel_dp->aux.dev = dev->dev;
 	intel_dp->aux.transfer = intel_dp_aux_transfer;
 
-	DRM_DEBUG_KMS("registering %s bus for %s\n", name,
+	DRM_DEBUG_KMS("registering %s bus for %s\n",
+		      intel_dp->aux.name,
 		      connector->base.kdev->kobj.name);
 
 	ret = drm_dp_aux_register(&intel_dp->aux);
 	if (ret < 0) {
 		DRM_ERROR("drm_dp_aux_register() for %s failed (%d)\n",
-			  name, ret);
-		return;
+			  intel_dp->aux.name, ret);
+		kfree(intel_dp->aux.name);
+		return ret;
 	}
 
 	ret = sysfs_create_link(&connector->base.kdev->kobj,
 				&intel_dp->aux.ddc.dev.kobj,
 				intel_dp->aux.ddc.dev.kobj.name);
 	if (ret < 0) {
-		DRM_ERROR("sysfs_create_link() for %s failed (%d)\n", name, ret);
-		drm_dp_aux_unregister(&intel_dp->aux);
+		DRM_ERROR("sysfs_create_link() for %s failed (%d)\n",
+			  intel_dp->aux.name, ret);
+		intel_dp_aux_fini(intel_dp);
+		return ret;
 	}
+
+	return 0;
 }
 
 static void
@@ -1186,10 +1297,13 @@
 	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
 }
 
-static bool intel_dp_source_supports_hbr2(struct drm_device *dev)
+bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
 {
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = dig_port->base.base.dev;
+
 	/* WaDisableHBR2:skl */
-	if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0)
+	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0))
 		return false;
 
 	if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) ||
@@ -1200,14 +1314,16 @@
 }
 
 static int
-intel_dp_source_rates(struct drm_device *dev, const int **source_rates)
+intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
 {
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = dig_port->base.base.dev;
 	int size;
 
 	if (IS_BROXTON(dev)) {
 		*source_rates = bxt_rates;
 		size = ARRAY_SIZE(bxt_rates);
-	} else if (IS_SKYLAKE(dev)) {
+	} else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
 		*source_rates = skl_rates;
 		size = ARRAY_SIZE(skl_rates);
 	} else {
@@ -1216,7 +1332,7 @@
 	}
 
 	/* This depends on the fact that 5.4 is last value in the array */
-	if (!intel_dp_source_supports_hbr2(dev))
+	if (!intel_dp_source_supports_hbr2(intel_dp))
 		size--;
 
 	return size;
@@ -1281,12 +1397,11 @@
 static int intel_dp_common_rates(struct intel_dp *intel_dp,
 				 int *common_rates)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 	const int *source_rates, *sink_rates;
 	int source_len, sink_len;
 
 	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
-	source_len = intel_dp_source_rates(dev, &source_rates);
+	source_len = intel_dp_source_rates(intel_dp, &source_rates);
 
 	return intersect_rates(source_rates, source_len,
 			       sink_rates, sink_len,
@@ -1311,7 +1426,6 @@
 
 static void intel_dp_print_rates(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 	const int *source_rates, *sink_rates;
 	int source_len, sink_len, common_len;
 	int common_rates[DP_MAX_SUPPORTED_RATES];
@@ -1320,7 +1434,7 @@
 	if ((drm_debug & DRM_UT_KMS) == 0)
 		return;
 
-	source_len = intel_dp_source_rates(dev, &source_rates);
+	source_len = intel_dp_source_rates(intel_dp, &source_rates);
 	snprintf_int_array(str, sizeof(str), source_rates, source_len);
 	DRM_DEBUG_KMS("source rates: %s\n", str);
 
@@ -1362,8 +1476,8 @@
 	return rate_to_index(rate, intel_dp->sink_rates);
 }
 
-static void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
-				  uint8_t *link_bw, uint8_t *rate_select)
+void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
+			   uint8_t *link_bw, uint8_t *rate_select)
 {
 	if (intel_dp->num_sink_rates) {
 		*link_bw = 0;
@@ -1423,7 +1537,7 @@
 				return ret;
 		}
 
-		if (!HAS_PCH_SPLIT(dev))
+		if (HAS_GMCH_DISPLAY(dev))
 			intel_gmch_panel_fitting(intel_crtc, pipe_config,
 						 intel_connector->panel.fitting_mode);
 		else
@@ -1527,7 +1641,7 @@
 				&pipe_config->dp_m2_n2);
 	}
 
-	if (IS_SKYLAKE(dev) && is_edp(intel_dp))
+	if ((IS_SKYLAKE(dev)  || IS_KABYLAKE(dev)) && is_edp(intel_dp))
 		skl_edp_set_pll_config(pipe_config);
 	else if (IS_BROXTON(dev))
 		/* handled in ddi */;
@@ -1539,37 +1653,6 @@
 	return true;
 }
 
-static void ironlake_set_pll_cpu_edp(struct intel_dp *intel_dp)
-{
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
-	struct drm_device *dev = crtc->base.dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 dpa_ctl;
-
-	DRM_DEBUG_KMS("eDP PLL enable for clock %d\n",
-		      crtc->config->port_clock);
-	dpa_ctl = I915_READ(DP_A);
-	dpa_ctl &= ~DP_PLL_FREQ_MASK;
-
-	if (crtc->config->port_clock == 162000) {
-		/* For a long time we've carried around a ILK-DevA w/a for the
-		 * 160MHz clock. If we're really unlucky, it's still required.
-		 */
-		DRM_DEBUG_KMS("160MHz cpu eDP clock, might need ilk devA w/a\n");
-		dpa_ctl |= DP_PLL_FREQ_160MHZ;
-		intel_dp->DP |= DP_PLL_FREQ_160MHZ;
-	} else {
-		dpa_ctl |= DP_PLL_FREQ_270MHZ;
-		intel_dp->DP |= DP_PLL_FREQ_270MHZ;
-	}
-
-	I915_WRITE(DP_A, dpa_ctl);
-
-	POSTING_READ(DP_A);
-	udelay(500);
-}
-
 void intel_dp_set_link_params(struct intel_dp *intel_dp,
 			      const struct intel_crtc_state *pipe_config)
 {
@@ -1614,9 +1697,6 @@
 	intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
 	intel_dp->DP |= DP_PORT_WIDTH(crtc->config->lane_count);
 
-	if (crtc->config->has_audio)
-		intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
-
 	/* Split out the IBX/CPU vs CPT settings */
 
 	if (IS_GEN7(dev) && port == PORT_A) {
@@ -1677,7 +1757,7 @@
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 pp_stat_reg, pp_ctrl_reg;
+	i915_reg_t pp_stat_reg, pp_ctrl_reg;
 
 	lockdep_assert_held(&dev_priv->pps_mutex);
 
@@ -1767,7 +1847,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	enum intel_display_power_domain power_domain;
 	u32 pp;
-	u32 pp_stat_reg, pp_ctrl_reg;
+	i915_reg_t pp_stat_reg, pp_ctrl_reg;
 	bool need_to_disable = !intel_dp->want_panel_vdd;
 
 	lockdep_assert_held(&dev_priv->pps_mutex);
@@ -1843,7 +1923,7 @@
 	struct intel_encoder *intel_encoder = &intel_dig_port->base;
 	enum intel_display_power_domain power_domain;
 	u32 pp;
-	u32 pp_stat_reg, pp_ctrl_reg;
+	i915_reg_t pp_stat_reg, pp_ctrl_reg;
 
 	lockdep_assert_held(&dev_priv->pps_mutex);
 
@@ -1930,7 +2010,7 @@
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 pp;
-	u32 pp_ctrl_reg;
+	i915_reg_t pp_ctrl_reg;
 
 	lockdep_assert_held(&dev_priv->pps_mutex);
 
@@ -1992,7 +2072,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	enum intel_display_power_domain power_domain;
 	u32 pp;
-	u32 pp_ctrl_reg;
+	i915_reg_t pp_ctrl_reg;
 
 	lockdep_assert_held(&dev_priv->pps_mutex);
 
@@ -2043,7 +2123,7 @@
 	struct drm_device *dev = intel_dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 pp;
-	u32 pp_ctrl_reg;
+	i915_reg_t pp_ctrl_reg;
 
 	/*
 	 * If we enable the backlight right away following a panel power
@@ -2084,7 +2164,7 @@
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 pp;
-	u32 pp_ctrl_reg;
+	i915_reg_t pp_ctrl_reg;
 
 	if (!is_edp(intel_dp))
 		return;
@@ -2143,27 +2223,61 @@
 		_intel_edp_backlight_off(intel_dp);
 }
 
+static const char *state_string(bool enabled)
+{
+	return enabled ? "on" : "off";
+}
+
+static void assert_dp_port(struct intel_dp *intel_dp, bool state)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+	bool cur_state = I915_READ(intel_dp->output_reg) & DP_PORT_EN;
+
+	I915_STATE_WARN(cur_state != state,
+			"DP port %c state assertion failure (expected %s, current %s)\n",
+			port_name(dig_port->port),
+			state_string(state), state_string(cur_state));
+}
+#define assert_dp_port_disabled(d) assert_dp_port((d), false)
+
+static void assert_edp_pll(struct drm_i915_private *dev_priv, bool state)
+{
+	bool cur_state = I915_READ(DP_A) & DP_PLL_ENABLE;
+
+	I915_STATE_WARN(cur_state != state,
+			"eDP PLL state assertion failure (expected %s, current %s)\n",
+			state_string(state), state_string(cur_state));
+}
+#define assert_edp_pll_enabled(d) assert_edp_pll((d), true)
+#define assert_edp_pll_disabled(d) assert_edp_pll((d), false)
+
 static void ironlake_edp_pll_on(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-	struct drm_crtc *crtc = intel_dig_port->base.base.crtc;
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 dpa_ctl;
+	struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
-	assert_pipe_disabled(dev_priv,
-			     to_intel_crtc(crtc)->pipe);
+	assert_pipe_disabled(dev_priv, crtc->pipe);
+	assert_dp_port_disabled(intel_dp);
+	assert_edp_pll_disabled(dev_priv);
 
-	DRM_DEBUG_KMS("\n");
-	dpa_ctl = I915_READ(DP_A);
-	WARN(dpa_ctl & DP_PLL_ENABLE, "dp pll on, should be off\n");
-	WARN(dpa_ctl & DP_PORT_EN, "dp port still on, should be off\n");
+	DRM_DEBUG_KMS("enabling eDP PLL for clock %d\n",
+		      crtc->config->port_clock);
 
-	/* We don't adjust intel_dp->DP while tearing down the link, to
-	 * facilitate link retraining (e.g. after hotplug). Hence clear all
-	 * enable bits here to ensure that we don't enable too much. */
-	intel_dp->DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE);
+	intel_dp->DP &= ~DP_PLL_FREQ_MASK;
+
+	if (crtc->config->port_clock == 162000)
+		intel_dp->DP |= DP_PLL_FREQ_162MHZ;
+	else
+		intel_dp->DP |= DP_PLL_FREQ_270MHZ;
+
+	I915_WRITE(DP_A, intel_dp->DP);
+	POSTING_READ(DP_A);
+	udelay(500);
+
 	intel_dp->DP |= DP_PLL_ENABLE;
+
 	I915_WRITE(DP_A, intel_dp->DP);
 	POSTING_READ(DP_A);
 	udelay(200);
@@ -2172,24 +2286,18 @@
 static void ironlake_edp_pll_off(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-	struct drm_crtc *crtc = intel_dig_port->base.base.crtc;
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 dpa_ctl;
+	struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
-	assert_pipe_disabled(dev_priv,
-			     to_intel_crtc(crtc)->pipe);
+	assert_pipe_disabled(dev_priv, crtc->pipe);
+	assert_dp_port_disabled(intel_dp);
+	assert_edp_pll_enabled(dev_priv);
 
-	dpa_ctl = I915_READ(DP_A);
-	WARN((dpa_ctl & DP_PLL_ENABLE) == 0,
-	     "dp pll off, should be on\n");
-	WARN(dpa_ctl & DP_PORT_EN, "dp port still on, should be off\n");
+	DRM_DEBUG_KMS("disabling eDP PLL\n");
 
-	/* We can't rely on the value tracked for the DP register in
-	 * intel_dp->DP because link_down must not change that (otherwise link
-	 * re-training will fail. */
-	dpa_ctl &= ~DP_PLL_ENABLE;
-	I915_WRITE(DP_A, dpa_ctl);
+	intel_dp->DP &= ~DP_PLL_ENABLE;
+
+	I915_WRITE(DP_A, intel_dp->DP);
 	POSTING_READ(DP_A);
 	udelay(200);
 }
@@ -2258,7 +2366,7 @@
 		}
 
 		DRM_DEBUG_KMS("No pipe for dp port 0x%x found\n",
-			      intel_dp->output_reg);
+			      i915_mmio_reg_offset(intel_dp->output_reg));
 	} else if (IS_CHERRYVIEW(dev)) {
 		*pipe = DP_PORT_TO_PIPE_CHV(tmp);
 	} else {
@@ -2321,7 +2429,7 @@
 	intel_dp_get_m_n(crtc, pipe_config);
 
 	if (port == PORT_A) {
-		if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_160MHZ)
+		if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_162MHZ)
 			pipe_config->port_clock = 162000;
 		else
 			pipe_config->port_clock = 270000;
@@ -2386,6 +2494,8 @@
 	enum port port = dp_to_dig_port(intel_dp)->port;
 
 	intel_dp_link_down(intel_dp);
+
+	/* Only ilk+ has port A */
 	if (port == PORT_A)
 		ironlake_edp_pll_off(intel_dp);
 }
@@ -2545,6 +2655,8 @@
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *crtc =
+		to_intel_crtc(dp_to_dig_port(intel_dp)->base.base.crtc);
 
 	/* enable with pattern 1 (as per spec) */
 	_intel_dp_set_link_train(intel_dp, &intel_dp->DP,
@@ -2560,6 +2672,8 @@
 	 * fail when the power sequencer is freshly used for this port.
 	 */
 	intel_dp->DP |= DP_PORT_EN;
+	if (crtc->config->has_audio)
+		intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
 
 	I915_WRITE(intel_dp->output_reg, intel_dp->DP);
 	POSTING_READ(intel_dp->output_reg);
@@ -2572,6 +2686,8 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
 	uint32_t dp_reg = I915_READ(intel_dp->output_reg);
+	enum port port = dp_to_dig_port(intel_dp)->port;
+	enum pipe pipe = crtc->pipe;
 
 	if (WARN_ON(dp_reg & DP_PORT_EN))
 		return;
@@ -2583,6 +2699,17 @@
 
 	intel_dp_enable_port(intel_dp);
 
+	if (port == PORT_A && IS_GEN5(dev_priv)) {
+		/*
+		 * Underrun reporting for the other pipe was disabled in
+		 * g4x_pre_enable_dp(). The eDP PLL and port have now been
+		 * enabled, so it's now safe to re-enable underrun reporting.
+		 */
+		intel_wait_for_vblank_if_active(dev_priv->dev, !pipe);
+		intel_set_cpu_fifo_underrun_reporting(dev_priv, !pipe, true);
+		intel_set_pch_fifo_underrun_reporting(dev_priv, !pipe, true);
+	}
+
 	edp_panel_vdd_on(intel_dp);
 	edp_panel_on(intel_dp);
 	edp_panel_vdd_off(intel_dp, true);
@@ -2605,7 +2732,7 @@
 
 	if (crtc->config->has_audio) {
 		DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
-				 pipe_name(crtc->pipe));
+				 pipe_name(pipe));
 		intel_audio_codec_enable(encoder);
 	}
 }
@@ -2628,16 +2755,29 @@
 
 static void g4x_pre_enable_dp(struct intel_encoder *encoder)
 {
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
-	struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
+	enum port port = dp_to_dig_port(intel_dp)->port;
+	enum pipe pipe = to_intel_crtc(encoder->base.crtc)->pipe;
 
 	intel_dp_prepare(encoder);
 
-	/* Only ilk+ has port A */
-	if (dport->port == PORT_A) {
-		ironlake_set_pll_cpu_edp(intel_dp);
-		ironlake_edp_pll_on(intel_dp);
+	if (port == PORT_A && IS_GEN5(dev_priv)) {
+		/*
+		 * We get FIFO underruns on the other pipe when
+		 * enabling the CPU eDP PLL, and when enabling CPU
+		 * eDP port. We could potentially avoid the PLL
+		 * underrun with a vblank wait just prior to enabling
+		 * the PLL, but that doesn't appear to help the port
+		 * enable case. Just sweep it all under the rug.
+		 */
+		intel_set_cpu_fifo_underrun_reporting(dev_priv, !pipe, false);
+		intel_set_pch_fifo_underrun_reporting(dev_priv, !pipe, false);
 	}
+
+	/* Only ilk+ has port A */
+	if (port == PORT_A)
+		ironlake_edp_pll_on(intel_dp);
 }
 
 static void vlv_detach_power_sequencer(struct intel_dp *intel_dp)
@@ -2645,7 +2785,7 @@
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 	struct drm_i915_private *dev_priv = intel_dig_port->base.base.dev->dev_private;
 	enum pipe pipe = intel_dp->pps_pipe;
-	int pp_on_reg = VLV_PIPE_PP_ON_DELAYS(pipe);
+	i915_reg_t pp_on_reg = VLV_PIPE_PP_ON_DELAYS(pipe);
 
 	edp_panel_vdd_off_sync(intel_dp);
 
@@ -3043,7 +3183,7 @@
  * Fetch AUX CH registers 0x202 - 0x207 which contain
  * link status information
  */
-static bool
+bool
 intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE])
 {
 	return intel_dp_dpcd_read_wake(&intel_dp->aux,
@@ -3053,7 +3193,7 @@
 }
 
 /* These are source-specific values. */
-static uint8_t
+uint8_t
 intel_dp_voltage_max(struct intel_dp *intel_dp)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -3076,7 +3216,7 @@
 		return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
 }
 
-static uint8_t
+uint8_t
 intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -3418,38 +3558,6 @@
 	return 0;
 }
 
-static void
-intel_get_adjust_train(struct intel_dp *intel_dp,
-		       const uint8_t link_status[DP_LINK_STATUS_SIZE])
-{
-	uint8_t v = 0;
-	uint8_t p = 0;
-	int lane;
-	uint8_t voltage_max;
-	uint8_t preemph_max;
-
-	for (lane = 0; lane < intel_dp->lane_count; lane++) {
-		uint8_t this_v = drm_dp_get_adjust_request_voltage(link_status, lane);
-		uint8_t this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
-
-		if (this_v > v)
-			v = this_v;
-		if (this_p > p)
-			p = this_p;
-	}
-
-	voltage_max = intel_dp_voltage_max(intel_dp);
-	if (v >= voltage_max)
-		v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
-
-	preemph_max = intel_dp_pre_emphasis_max(intel_dp, v);
-	if (p >= preemph_max)
-		p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
-
-	for (lane = 0; lane < 4; lane++)
-		intel_dp->train_set[lane] = v | p;
-}
-
 static uint32_t
 gen4_signal_levels(uint8_t train_set)
 {
@@ -3547,13 +3655,13 @@
 	}
 }
 
-/* Properly updates "DP" with the correct signal levels. */
-static void
-intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
+void
+intel_dp_set_signal_levels(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 	enum port port = intel_dig_port->port;
 	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
 	uint32_t signal_levels, mask = 0;
 	uint8_t train_set = intel_dp->train_set[0];
 
@@ -3588,74 +3696,27 @@
 		(train_set & DP_TRAIN_PRE_EMPHASIS_MASK) >>
 			DP_TRAIN_PRE_EMPHASIS_SHIFT);
 
-	*DP = (*DP & ~mask) | signal_levels;
+	intel_dp->DP = (intel_dp->DP & ~mask) | signal_levels;
+
+	I915_WRITE(intel_dp->output_reg, intel_dp->DP);
+	POSTING_READ(intel_dp->output_reg);
 }
 
-static bool
-intel_dp_set_link_train(struct intel_dp *intel_dp,
-			uint32_t *DP,
-			uint8_t dp_train_pat)
+void
+intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
+				       uint8_t dp_train_pat)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 	struct drm_i915_private *dev_priv =
 		to_i915(intel_dig_port->base.base.dev);
-	uint8_t buf[sizeof(intel_dp->train_set) + 1];
-	int ret, len;
 
-	_intel_dp_set_link_train(intel_dp, DP, dp_train_pat);
+	_intel_dp_set_link_train(intel_dp, &intel_dp->DP, dp_train_pat);
 
-	I915_WRITE(intel_dp->output_reg, *DP);
+	I915_WRITE(intel_dp->output_reg, intel_dp->DP);
 	POSTING_READ(intel_dp->output_reg);
-
-	buf[0] = dp_train_pat;
-	if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
-	    DP_TRAINING_PATTERN_DISABLE) {
-		/* don't write DP_TRAINING_LANEx_SET on disable */
-		len = 1;
-	} else {
-		/* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
-		memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
-		len = intel_dp->lane_count + 1;
-	}
-
-	ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
-				buf, len);
-
-	return ret == len;
 }
 
-static bool
-intel_dp_reset_link_train(struct intel_dp *intel_dp, uint32_t *DP,
-			uint8_t dp_train_pat)
-{
-	if (!intel_dp->train_set_valid)
-		memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
-	intel_dp_set_signal_levels(intel_dp, DP);
-	return intel_dp_set_link_train(intel_dp, DP, dp_train_pat);
-}
-
-static bool
-intel_dp_update_link_train(struct intel_dp *intel_dp, uint32_t *DP,
-			   const uint8_t link_status[DP_LINK_STATUS_SIZE])
-{
-	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-	struct drm_i915_private *dev_priv =
-		to_i915(intel_dig_port->base.base.dev);
-	int ret;
-
-	intel_get_adjust_train(intel_dp, link_status);
-	intel_dp_set_signal_levels(intel_dp, DP);
-
-	I915_WRITE(intel_dp->output_reg, *DP);
-	POSTING_READ(intel_dp->output_reg);
-
-	ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
-				intel_dp->train_set, intel_dp->lane_count);
-
-	return ret == intel_dp->lane_count;
-}
-
-static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
+void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 	struct drm_device *dev = intel_dig_port->base.base.dev;
@@ -3686,232 +3747,6 @@
 		DRM_ERROR("Timed out waiting for DP idle patterns\n");
 }
 
-/* Enable corresponding port and start training pattern 1 */
-static void
-intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
-{
-	struct drm_encoder *encoder = &dp_to_dig_port(intel_dp)->base.base;
-	struct drm_device *dev = encoder->dev;
-	int i;
-	uint8_t voltage;
-	int voltage_tries, loop_tries;
-	uint32_t DP = intel_dp->DP;
-	uint8_t link_config[2];
-	uint8_t link_bw, rate_select;
-
-	if (HAS_DDI(dev))
-		intel_ddi_prepare_link_retrain(encoder);
-
-	intel_dp_compute_rate(intel_dp, intel_dp->link_rate,
-			      &link_bw, &rate_select);
-
-	/* Write the link configuration data */
-	link_config[0] = link_bw;
-	link_config[1] = intel_dp->lane_count;
-	if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
-		link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
-	drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
-	if (intel_dp->num_sink_rates)
-		drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
-				  &rate_select, 1);
-
-	link_config[0] = 0;
-	link_config[1] = DP_SET_ANSI_8B10B;
-	drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
-
-	DP |= DP_PORT_EN;
-
-	/* clock recovery */
-	if (!intel_dp_reset_link_train(intel_dp, &DP,
-				       DP_TRAINING_PATTERN_1 |
-				       DP_LINK_SCRAMBLING_DISABLE)) {
-		DRM_ERROR("failed to enable link training\n");
-		return;
-	}
-
-	voltage = 0xff;
-	voltage_tries = 0;
-	loop_tries = 0;
-	for (;;) {
-		uint8_t link_status[DP_LINK_STATUS_SIZE];
-
-		drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
-		if (!intel_dp_get_link_status(intel_dp, link_status)) {
-			DRM_ERROR("failed to get link status\n");
-			break;
-		}
-
-		if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
-			DRM_DEBUG_KMS("clock recovery OK\n");
-			break;
-		}
-
-		/*
-		 * if we used previously trained voltage and pre-emphasis values
-		 * and we don't get clock recovery, reset link training values
-		 */
-		if (intel_dp->train_set_valid) {
-			DRM_DEBUG_KMS("clock recovery not ok, reset");
-			/* clear the flag as we are not reusing train set */
-			intel_dp->train_set_valid = false;
-			if (!intel_dp_reset_link_train(intel_dp, &DP,
-						       DP_TRAINING_PATTERN_1 |
-						       DP_LINK_SCRAMBLING_DISABLE)) {
-				DRM_ERROR("failed to enable link training\n");
-				return;
-			}
-			continue;
-		}
-
-		/* Check to see if we've tried the max voltage */
-		for (i = 0; i < intel_dp->lane_count; i++)
-			if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
-				break;
-		if (i == intel_dp->lane_count) {
-			++loop_tries;
-			if (loop_tries == 5) {
-				DRM_ERROR("too many full retries, give up\n");
-				break;
-			}
-			intel_dp_reset_link_train(intel_dp, &DP,
-						  DP_TRAINING_PATTERN_1 |
-						  DP_LINK_SCRAMBLING_DISABLE);
-			voltage_tries = 0;
-			continue;
-		}
-
-		/* Check to see if we've tried the same voltage 5 times */
-		if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
-			++voltage_tries;
-			if (voltage_tries == 5) {
-				DRM_ERROR("too many voltage retries, give up\n");
-				break;
-			}
-		} else
-			voltage_tries = 0;
-		voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
-
-		/* Update training set as requested by target */
-		if (!intel_dp_update_link_train(intel_dp, &DP, link_status)) {
-			DRM_ERROR("failed to update link training\n");
-			break;
-		}
-	}
-
-	intel_dp->DP = DP;
-}
-
-static void
-intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
-{
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct drm_device *dev = dig_port->base.base.dev;
-	bool channel_eq = false;
-	int tries, cr_tries;
-	uint32_t DP = intel_dp->DP;
-	uint32_t training_pattern = DP_TRAINING_PATTERN_2;
-
-	/*
-	 * Training Pattern 3 for HBR2 or 1.2 devices that support it.
-	 *
-	 * Intel platforms that support HBR2 also support TPS3. TPS3 support is
-	 * also mandatory for downstream devices that support HBR2.
-	 *
-	 * Due to WaDisableHBR2 SKL < B0 is the only exception where TPS3 is
-	 * supported but still not enabled.
-	 */
-	if (intel_dp_source_supports_hbr2(dev) &&
-	    drm_dp_tps3_supported(intel_dp->dpcd))
-		training_pattern = DP_TRAINING_PATTERN_3;
-	else if (intel_dp->link_rate == 540000)
-		DRM_ERROR("5.4 Gbps link rate without HBR2/TPS3 support\n");
-
-	/* channel equalization */
-	if (!intel_dp_set_link_train(intel_dp, &DP,
-				     training_pattern |
-				     DP_LINK_SCRAMBLING_DISABLE)) {
-		DRM_ERROR("failed to start channel equalization\n");
-		return;
-	}
-
-	tries = 0;
-	cr_tries = 0;
-	channel_eq = false;
-	for (;;) {
-		uint8_t link_status[DP_LINK_STATUS_SIZE];
-
-		if (cr_tries > 5) {
-			DRM_ERROR("failed to train DP, aborting\n");
-			break;
-		}
-
-		drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
-		if (!intel_dp_get_link_status(intel_dp, link_status)) {
-			DRM_ERROR("failed to get link status\n");
-			break;
-		}
-
-		/* Make sure clock is still ok */
-		if (!drm_dp_clock_recovery_ok(link_status,
-					      intel_dp->lane_count)) {
-			intel_dp->train_set_valid = false;
-			intel_dp_link_training_clock_recovery(intel_dp);
-			intel_dp_set_link_train(intel_dp, &DP,
-						training_pattern |
-						DP_LINK_SCRAMBLING_DISABLE);
-			cr_tries++;
-			continue;
-		}
-
-		if (drm_dp_channel_eq_ok(link_status,
-					 intel_dp->lane_count)) {
-			channel_eq = true;
-			break;
-		}
-
-		/* Try 5 times, then try clock recovery if that fails */
-		if (tries > 5) {
-			intel_dp->train_set_valid = false;
-			intel_dp_link_training_clock_recovery(intel_dp);
-			intel_dp_set_link_train(intel_dp, &DP,
-						training_pattern |
-						DP_LINK_SCRAMBLING_DISABLE);
-			tries = 0;
-			cr_tries++;
-			continue;
-		}
-
-		/* Update training set as requested by target */
-		if (!intel_dp_update_link_train(intel_dp, &DP, link_status)) {
-			DRM_ERROR("failed to update link training\n");
-			break;
-		}
-		++tries;
-	}
-
-	intel_dp_set_idle_link_train(intel_dp);
-
-	intel_dp->DP = DP;
-
-	if (channel_eq) {
-		intel_dp->train_set_valid = true;
-		DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n");
-	}
-}
-
-void intel_dp_stop_link_train(struct intel_dp *intel_dp)
-{
-	intel_dp_set_link_train(intel_dp, &intel_dp->DP,
-				DP_TRAINING_PATTERN_DISABLE);
-}
-
-void
-intel_dp_start_link_train(struct intel_dp *intel_dp)
-{
-	intel_dp_link_training_clock_recovery(intel_dp);
-	intel_dp_link_training_channel_equalization(intel_dp);
-}
-
 static void
 intel_dp_link_down(struct intel_dp *intel_dp)
 {
@@ -3954,6 +3789,13 @@
 	 * matching HDMI port to be enabled on transcoder A.
 	 */
 	if (HAS_PCH_IBX(dev) && crtc->pipe == PIPE_B && port != PORT_A) {
+		/*
+		 * We get CPU/PCH FIFO underruns on the other pipe when
+		 * doing the workaround. Sweep them under the rug.
+		 */
+		intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+		intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+
 		/* always enable with pattern 1 (as per spec) */
 		DP &= ~(DP_PIPEB_SELECT | DP_LINK_TRAIN_MASK);
 		DP |= DP_PORT_EN | DP_LINK_TRAIN_PAT_1;
@@ -3963,9 +3805,15 @@
 		DP &= ~DP_PORT_EN;
 		I915_WRITE(intel_dp->output_reg, DP);
 		POSTING_READ(intel_dp->output_reg);
+
+		intel_wait_for_vblank_if_active(dev_priv->dev, PIPE_A);
+		intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
+		intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
 	}
 
 	msleep(intel_dp->panel_power_down_delay);
+
+	intel_dp->DP = DP;
 }
 
 static bool
@@ -4013,7 +3861,7 @@
 	}
 
 	DRM_DEBUG_KMS("Display Port TPS3 support: source %s, sink %s\n",
-		      yesno(intel_dp_source_supports_hbr2(dev)),
+		      yesno(intel_dp_source_supports_hbr2(intel_dp)),
 		      yesno(drm_dp_tps3_supported(intel_dp->dpcd)));
 
 	/* Intermediate frequency support */
@@ -4103,9 +3951,12 @@
 static int intel_dp_sink_crc_stop(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = dig_port->base.base.dev;
 	struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
 	u8 buf;
 	int ret = 0;
+	int count = 0;
+	int attempts = 10;
 
 	if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) {
 		DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n");
@@ -4120,7 +3971,22 @@
 		goto out;
 	}
 
-	intel_dp->sink_crc.started = false;
+	do {
+		intel_wait_for_vblank(dev, intel_crtc->pipe);
+
+		if (drm_dp_dpcd_readb(&intel_dp->aux,
+				      DP_TEST_SINK_MISC, &buf) < 0) {
+			ret = -EIO;
+			goto out;
+		}
+		count = buf & DP_TEST_COUNT_MASK;
+	} while (--attempts && count);
+
+	if (attempts == 0) {
+		DRM_ERROR("TIMEOUT: Sink CRC counter is not zeroed\n");
+		ret = -ETIMEDOUT;
+	}
+
  out:
 	hsw_enable_ips(intel_crtc);
 	return ret;
@@ -4129,27 +3995,26 @@
 static int intel_dp_sink_crc_start(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = dig_port->base.base.dev;
 	struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
 	u8 buf;
 	int ret;
 
-	if (intel_dp->sink_crc.started) {
-		ret = intel_dp_sink_crc_stop(intel_dp);
-		if (ret)
-			return ret;
-	}
-
 	if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0)
 		return -EIO;
 
 	if (!(buf & DP_TEST_CRC_SUPPORTED))
 		return -ENOTTY;
 
-	intel_dp->sink_crc.last_count = buf & DP_TEST_COUNT_MASK;
-
 	if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0)
 		return -EIO;
 
+	if (buf & DP_TEST_SINK_START) {
+		ret = intel_dp_sink_crc_stop(intel_dp);
+		if (ret)
+			return ret;
+	}
+
 	hsw_disable_ips(intel_crtc);
 
 	if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK,
@@ -4158,7 +4023,7 @@
 		return -EIO;
 	}
 
-	intel_dp->sink_crc.started = true;
+	intel_wait_for_vblank(dev, intel_crtc->pipe);
 	return 0;
 }
 
@@ -4170,7 +4035,6 @@
 	u8 buf;
 	int count, ret;
 	int attempts = 6;
-	bool old_equal_new;
 
 	ret = intel_dp_sink_crc_start(intel_dp);
 	if (ret)
@@ -4186,35 +4050,17 @@
 		}
 		count = buf & DP_TEST_COUNT_MASK;
 
-		/*
-		 * Count might be reset during the loop. In this case
-		 * last known count needs to be reset as well.
-		 */
-		if (count == 0)
-			intel_dp->sink_crc.last_count = 0;
-
-		if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0) {
-			ret = -EIO;
-			goto stop;
-		}
-
-		old_equal_new = (count == intel_dp->sink_crc.last_count &&
-				 !memcmp(intel_dp->sink_crc.last_crc, crc,
-					 6 * sizeof(u8)));
-
-	} while (--attempts && (count == 0 || old_equal_new));
-
-	intel_dp->sink_crc.last_count = buf & DP_TEST_COUNT_MASK;
-	memcpy(intel_dp->sink_crc.last_crc, crc, 6 * sizeof(u8));
+	} while (--attempts && count == 0);
 
 	if (attempts == 0) {
-		if (old_equal_new) {
-			DRM_DEBUG_KMS("Unreliable Sink CRC counter: Current returned CRC is identical to the previous one\n");
-		} else {
-			DRM_ERROR("Panel is unable to calculate any CRC after 6 vblanks\n");
-			ret = -ETIMEDOUT;
-			goto stop;
-		}
+		DRM_ERROR("Panel is unable to calculate any CRC after 6 vblanks\n");
+		ret = -ETIMEDOUT;
+		goto stop;
+	}
+
+	if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0) {
+		ret = -EIO;
+		goto stop;
 	}
 
 stop:
@@ -4314,13 +4160,6 @@
 	uint8_t rxdata = 0;
 	int status = 0;
 
-	intel_dp->compliance_test_active = 0;
-	intel_dp->compliance_test_type = 0;
-	intel_dp->compliance_test_data = 0;
-
-	intel_dp->aux.i2c_nack_count = 0;
-	intel_dp->aux.i2c_defer_count = 0;
-
 	status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_REQUEST, &rxdata, 1);
 	if (status <= 0) {
 		DRM_DEBUG_KMS("Could not read test request from sink\n");
@@ -4436,6 +4275,14 @@
 
 	WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
 
+	/*
+	 * Clearing compliance test variables to allow capturing
+	 * of values for next automated test request.
+	 */
+	intel_dp->compliance_test_active = 0;
+	intel_dp->compliance_test_type = 0;
+	intel_dp->compliance_test_data = 0;
+
 	if (!intel_encoder->base.crtc)
 		return;
 
@@ -4466,7 +4313,9 @@
 			DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n");
 	}
 
-	if (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) {
+	/* if link training is requested we should perform it always */
+	if ((intel_dp->compliance_test_type == DP_TEST_LINK_TRAINING) ||
+		(!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count))) {
 		DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
 			      intel_encoder->base.name);
 		intel_dp_start_link_train(intel_dp);
@@ -4684,41 +4533,6 @@
 		return g4x_digital_port_connected(dev_priv, port);
 }
 
-static enum drm_connector_status
-ironlake_dp_detect(struct intel_dp *intel_dp)
-{
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-
-	if (!intel_digital_port_connected(dev_priv, intel_dig_port))
-		return connector_status_disconnected;
-
-	return intel_dp_detect_dpcd(intel_dp);
-}
-
-static enum drm_connector_status
-g4x_dp_detect(struct intel_dp *intel_dp)
-{
-	struct drm_device *dev = intel_dp_to_dev(intel_dp);
-	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-
-	/* Can't disconnect eDP, but you can close the lid... */
-	if (is_edp(intel_dp)) {
-		enum drm_connector_status status;
-
-		status = intel_panel_detect(dev);
-		if (status == connector_status_unknown)
-			status = connector_status_connected;
-		return status;
-	}
-
-	if (!intel_digital_port_connected(dev->dev_private, intel_dig_port))
-		return connector_status_disconnected;
-
-	return intel_dp_detect_dpcd(intel_dp);
-}
-
 static struct edid *
 intel_dp_get_edid(struct intel_dp *intel_dp)
 {
@@ -4791,12 +4605,19 @@
 	/* Can't disconnect eDP, but you can close the lid... */
 	if (is_edp(intel_dp))
 		status = edp_detect(intel_dp);
-	else if (HAS_PCH_SPLIT(dev))
-		status = ironlake_dp_detect(intel_dp);
+	else if (intel_digital_port_connected(to_i915(dev),
+					      dp_to_dig_port(intel_dp)))
+		status = intel_dp_detect_dpcd(intel_dp);
 	else
-		status = g4x_dp_detect(intel_dp);
-	if (status != connector_status_connected)
+		status = connector_status_disconnected;
+
+	if (status != connector_status_connected) {
+		intel_dp->compliance_test_active = 0;
+		intel_dp->compliance_test_type = 0;
+		intel_dp->compliance_test_data = 0;
+
 		goto out;
+	}
 
 	intel_dp_probe_oui(intel_dp);
 
@@ -4810,6 +4631,14 @@
 		goto out;
 	}
 
+	/*
+	 * Clearing NACK and defer counts to get their exact values
+	 * while reading EDID which are required by Compliance tests
+	 * 4.2.2.4 and 4.2.2.5
+	 */
+	intel_dp->aux.i2c_nack_count = 0;
+	intel_dp->aux.i2c_defer_count = 0;
+
 	intel_dp_set_edid(intel_dp);
 
 	if (intel_encoder->type != INTEL_OUTPUT_EDP)
@@ -5014,7 +4843,7 @@
 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 	struct intel_dp *intel_dp = &intel_dig_port->dp;
 
-	drm_dp_aux_unregister(&intel_dp->aux);
+	intel_dp_aux_fini(intel_dp);
 	intel_dp_mst_encoder_cleanup(intel_dig_port);
 	if (is_edp(intel_dp)) {
 		cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
@@ -5204,25 +5033,6 @@
 	return ret;
 }
 
-/* Return which DP Port should be selected for Transcoder DP control */
-int
-intel_trans_dp_port_sel(struct drm_crtc *crtc)
-{
-	struct drm_device *dev = crtc->dev;
-	struct intel_encoder *intel_encoder;
-	struct intel_dp *intel_dp;
-
-	for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
-		intel_dp = enc_to_intel_dp(&intel_encoder->base);
-
-		if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
-		    intel_encoder->type == INTEL_OUTPUT_EDP)
-			return intel_dp->output_reg;
-	}
-
-	return -1;
-}
-
 /* check the VBT to see whether the eDP is on another port */
 bool intel_dp_is_edp(struct drm_device *dev, enum port port)
 {
@@ -5294,7 +5104,7 @@
 	struct edp_power_seq cur, vbt, spec,
 		*final = &intel_dp->pps_delays;
 	u32 pp_on, pp_off, pp_div = 0, pp_ctl = 0;
-	int pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg = 0;
+	i915_reg_t pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg;
 
 	lockdep_assert_held(&dev_priv->pps_mutex);
 
@@ -5416,7 +5226,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 pp_on, pp_off, pp_div, port_sel = 0;
 	int div = HAS_PCH_SPLIT(dev) ? intel_pch_rawclk(dev) : intel_hrawclk(dev);
-	int pp_on_reg, pp_off_reg, pp_div_reg = 0, pp_ctrl_reg;
+	i915_reg_t pp_on_reg, pp_off_reg, pp_div_reg, pp_ctrl_reg;
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	const struct edp_power_seq *seq = &intel_dp->pps_delays;
 
@@ -5578,7 +5388,7 @@
 			DRM_ERROR("Unsupported refreshrate type\n");
 		}
 	} else if (INTEL_INFO(dev)->gen > 6) {
-		u32 reg = PIPECONF(intel_crtc->config->cpu_transcoder);
+		i915_reg_t reg = PIPECONF(intel_crtc->config->cpu_transcoder);
 		u32 val;
 
 		val = I915_READ(reg);
@@ -5996,7 +5806,7 @@
 	struct drm_device *dev = intel_encoder->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	enum port port = intel_dig_port->port;
-	int type;
+	int type, ret;
 
 	intel_dp->pps_pipe = INVALID_PIPE;
 
@@ -6017,6 +5827,9 @@
 	else
 		intel_dp->get_aux_send_ctl = i9xx_get_aux_send_ctl;
 
+	if (HAS_DDI(dev))
+		intel_dp->prepare_link_retrain = intel_ddi_prepare_link_retrain;
+
 	/* Preserve the current hw state. */
 	intel_dp->DP = I915_READ(intel_dp->output_reg);
 	intel_dp->attached_connector = intel_connector;
@@ -6068,7 +5881,7 @@
 		break;
 	case PORT_B:
 		intel_encoder->hpd_pin = HPD_PORT_B;
-		if (IS_BROXTON(dev_priv) && (INTEL_REVID(dev) < BXT_REVID_B0))
+		if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
 			intel_encoder->hpd_pin = HPD_PORT_A;
 		break;
 	case PORT_C:
@@ -6094,7 +5907,9 @@
 		pps_unlock(intel_dp);
 	}
 
-	intel_dp_aux_init(intel_dp, intel_connector);
+	ret = intel_dp_aux_init(intel_dp, intel_connector);
+	if (ret)
+		goto fail;
 
 	/* init MST on ports that can support it */
 	if (HAS_DP_MST(dev) &&
@@ -6103,20 +5918,9 @@
 					  intel_connector->base.base.id);
 
 	if (!intel_edp_init_connector(intel_dp, intel_connector)) {
-		drm_dp_aux_unregister(&intel_dp->aux);
-		if (is_edp(intel_dp)) {
-			cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
-			/*
-			 * vdd might still be enabled do to the delayed vdd off.
-			 * Make sure vdd is actually turned off here.
-			 */
-			pps_lock(intel_dp);
-			edp_panel_vdd_off_sync(intel_dp);
-			pps_unlock(intel_dp);
-		}
-		drm_connector_unregister(connector);
-		drm_connector_cleanup(connector);
-		return false;
+		intel_dp_aux_fini(intel_dp);
+		intel_dp_mst_encoder_cleanup(intel_dig_port);
+		goto fail;
 	}
 
 	intel_dp_add_properties(intel_dp, connector);
@@ -6133,10 +5937,27 @@
 	i915_debugfs_connector_add(connector);
 
 	return true;
+
+fail:
+	if (is_edp(intel_dp)) {
+		cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
+		/*
+		 * vdd might still be enabled do to the delayed vdd off.
+		 * Make sure vdd is actually turned off here.
+		 */
+		pps_lock(intel_dp);
+		edp_panel_vdd_off_sync(intel_dp);
+		pps_unlock(intel_dp);
+	}
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+
+	return false;
 }
 
 void
-intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
+intel_dp_init(struct drm_device *dev,
+	      i915_reg_t output_reg, enum port port)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_digital_port *intel_dig_port;
@@ -6182,6 +6003,7 @@
 	}
 
 	intel_dig_port->port = port;
+	dev_priv->dig_port_map[port] = intel_encoder;
 	intel_dig_port->dp.output_reg = output_reg;
 
 	intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
new file mode 100644
index 0000000..8888793
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright © 2008-2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "intel_drv.h"
+
+static void
+intel_get_adjust_train(struct intel_dp *intel_dp,
+		       const uint8_t link_status[DP_LINK_STATUS_SIZE])
+{
+	uint8_t v = 0;
+	uint8_t p = 0;
+	int lane;
+	uint8_t voltage_max;
+	uint8_t preemph_max;
+
+	for (lane = 0; lane < intel_dp->lane_count; lane++) {
+		uint8_t this_v = drm_dp_get_adjust_request_voltage(link_status, lane);
+		uint8_t this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
+
+		if (this_v > v)
+			v = this_v;
+		if (this_p > p)
+			p = this_p;
+	}
+
+	voltage_max = intel_dp_voltage_max(intel_dp);
+	if (v >= voltage_max)
+		v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
+
+	preemph_max = intel_dp_pre_emphasis_max(intel_dp, v);
+	if (p >= preemph_max)
+		p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+
+	for (lane = 0; lane < 4; lane++)
+		intel_dp->train_set[lane] = v | p;
+}
+
+static bool
+intel_dp_set_link_train(struct intel_dp *intel_dp,
+			uint8_t dp_train_pat)
+{
+	uint8_t buf[sizeof(intel_dp->train_set) + 1];
+	int ret, len;
+
+	intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
+
+	buf[0] = dp_train_pat;
+	if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
+	    DP_TRAINING_PATTERN_DISABLE) {
+		/* don't write DP_TRAINING_LANEx_SET on disable */
+		len = 1;
+	} else {
+		/* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
+		memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
+		len = intel_dp->lane_count + 1;
+	}
+
+	ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
+				buf, len);
+
+	return ret == len;
+}
+
+static bool
+intel_dp_reset_link_train(struct intel_dp *intel_dp,
+			uint8_t dp_train_pat)
+{
+	if (!intel_dp->train_set_valid)
+		memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
+	intel_dp_set_signal_levels(intel_dp);
+	return intel_dp_set_link_train(intel_dp, dp_train_pat);
+}
+
+static bool
+intel_dp_update_link_train(struct intel_dp *intel_dp)
+{
+	int ret;
+
+	intel_dp_set_signal_levels(intel_dp);
+
+	ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
+				intel_dp->train_set, intel_dp->lane_count);
+
+	return ret == intel_dp->lane_count;
+}
+
+/* Enable corresponding port and start training pattern 1 */
+static void
+intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
+{
+	int i;
+	uint8_t voltage;
+	int voltage_tries, loop_tries;
+	uint8_t link_config[2];
+	uint8_t link_bw, rate_select;
+
+	if (intel_dp->prepare_link_retrain)
+		intel_dp->prepare_link_retrain(intel_dp);
+
+	intel_dp_compute_rate(intel_dp, intel_dp->link_rate,
+			      &link_bw, &rate_select);
+
+	/* Write the link configuration data */
+	link_config[0] = link_bw;
+	link_config[1] = intel_dp->lane_count;
+	if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
+		link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+	drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
+	if (intel_dp->num_sink_rates)
+		drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
+				  &rate_select, 1);
+
+	link_config[0] = 0;
+	link_config[1] = DP_SET_ANSI_8B10B;
+	drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
+
+	intel_dp->DP |= DP_PORT_EN;
+
+	/* clock recovery */
+	if (!intel_dp_reset_link_train(intel_dp,
+				       DP_TRAINING_PATTERN_1 |
+				       DP_LINK_SCRAMBLING_DISABLE)) {
+		DRM_ERROR("failed to enable link training\n");
+		return;
+	}
+
+	voltage = 0xff;
+	voltage_tries = 0;
+	loop_tries = 0;
+	for (;;) {
+		uint8_t link_status[DP_LINK_STATUS_SIZE];
+
+		drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
+		if (!intel_dp_get_link_status(intel_dp, link_status)) {
+			DRM_ERROR("failed to get link status\n");
+			break;
+		}
+
+		if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
+			DRM_DEBUG_KMS("clock recovery OK\n");
+			break;
+		}
+
+		/*
+		 * if we used previously trained voltage and pre-emphasis values
+		 * and we don't get clock recovery, reset link training values
+		 */
+		if (intel_dp->train_set_valid) {
+			DRM_DEBUG_KMS("clock recovery not ok, reset");
+			/* clear the flag as we are not reusing train set */
+			intel_dp->train_set_valid = false;
+			if (!intel_dp_reset_link_train(intel_dp,
+						       DP_TRAINING_PATTERN_1 |
+						       DP_LINK_SCRAMBLING_DISABLE)) {
+				DRM_ERROR("failed to enable link training\n");
+				return;
+			}
+			continue;
+		}
+
+		/* Check to see if we've tried the max voltage */
+		for (i = 0; i < intel_dp->lane_count; i++)
+			if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+				break;
+		if (i == intel_dp->lane_count) {
+			++loop_tries;
+			if (loop_tries == 5) {
+				DRM_ERROR("too many full retries, give up\n");
+				break;
+			}
+			intel_dp_reset_link_train(intel_dp,
+						  DP_TRAINING_PATTERN_1 |
+						  DP_LINK_SCRAMBLING_DISABLE);
+			voltage_tries = 0;
+			continue;
+		}
+
+		/* Check to see if we've tried the same voltage 5 times */
+		if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+			++voltage_tries;
+			if (voltage_tries == 5) {
+				DRM_ERROR("too many voltage retries, give up\n");
+				break;
+			}
+		} else
+			voltage_tries = 0;
+		voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+
+		/* Update training set as requested by target */
+		intel_get_adjust_train(intel_dp, link_status);
+		if (!intel_dp_update_link_train(intel_dp)) {
+			DRM_ERROR("failed to update link training\n");
+			break;
+		}
+	}
+}
+
+static void
+intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
+{
+	bool channel_eq = false;
+	int tries, cr_tries;
+	uint32_t training_pattern = DP_TRAINING_PATTERN_2;
+
+	/*
+	 * Training Pattern 3 for HBR2 or 1.2 devices that support it.
+	 *
+	 * Intel platforms that support HBR2 also support TPS3. TPS3 support is
+	 * also mandatory for downstream devices that support HBR2.
+	 *
+	 * Due to WaDisableHBR2 SKL < B0 is the only exception where TPS3 is
+	 * supported but still not enabled.
+	 */
+	if (intel_dp_source_supports_hbr2(intel_dp) &&
+	    drm_dp_tps3_supported(intel_dp->dpcd))
+		training_pattern = DP_TRAINING_PATTERN_3;
+	else if (intel_dp->link_rate == 540000)
+		DRM_ERROR("5.4 Gbps link rate without HBR2/TPS3 support\n");
+
+	/* channel equalization */
+	if (!intel_dp_set_link_train(intel_dp,
+				     training_pattern |
+				     DP_LINK_SCRAMBLING_DISABLE)) {
+		DRM_ERROR("failed to start channel equalization\n");
+		return;
+	}
+
+	tries = 0;
+	cr_tries = 0;
+	channel_eq = false;
+	for (;;) {
+		uint8_t link_status[DP_LINK_STATUS_SIZE];
+
+		if (cr_tries > 5) {
+			DRM_ERROR("failed to train DP, aborting\n");
+			break;
+		}
+
+		drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
+		if (!intel_dp_get_link_status(intel_dp, link_status)) {
+			DRM_ERROR("failed to get link status\n");
+			break;
+		}
+
+		/* Make sure clock is still ok */
+		if (!drm_dp_clock_recovery_ok(link_status,
+					      intel_dp->lane_count)) {
+			intel_dp->train_set_valid = false;
+			intel_dp_link_training_clock_recovery(intel_dp);
+			intel_dp_set_link_train(intel_dp,
+						training_pattern |
+						DP_LINK_SCRAMBLING_DISABLE);
+			cr_tries++;
+			continue;
+		}
+
+		if (drm_dp_channel_eq_ok(link_status,
+					 intel_dp->lane_count)) {
+			channel_eq = true;
+			break;
+		}
+
+		/* Try 5 times, then try clock recovery if that fails */
+		if (tries > 5) {
+			intel_dp->train_set_valid = false;
+			intel_dp_link_training_clock_recovery(intel_dp);
+			intel_dp_set_link_train(intel_dp,
+						training_pattern |
+						DP_LINK_SCRAMBLING_DISABLE);
+			tries = 0;
+			cr_tries++;
+			continue;
+		}
+
+		/* Update training set as requested by target */
+		intel_get_adjust_train(intel_dp, link_status);
+		if (!intel_dp_update_link_train(intel_dp)) {
+			DRM_ERROR("failed to update link training\n");
+			break;
+		}
+		++tries;
+	}
+
+	intel_dp_set_idle_link_train(intel_dp);
+
+	if (channel_eq) {
+		intel_dp->train_set_valid = true;
+		DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n");
+	}
+}
+
+void intel_dp_stop_link_train(struct intel_dp *intel_dp)
+{
+	intel_dp_set_link_train(intel_dp,
+				DP_TRAINING_PATTERN_DISABLE);
+}
+
+void
+intel_dp_start_link_train(struct intel_dp *intel_dp)
+{
+	intel_dp_link_training_clock_recovery(intel_dp);
+	intel_dp_link_training_channel_equalization(intel_dp);
+}
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index 0639275..8c4e7df 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -173,20 +173,14 @@
 	intel_mst->port = found->port;
 
 	if (intel_dp->active_mst_links == 0) {
-		enum port port = intel_ddi_get_encoder_port(encoder);
+		intel_ddi_clk_select(encoder, intel_crtc->config);
 
 		intel_dp_set_link_params(intel_dp, intel_crtc->config);
 
-		/* FIXME: add support for SKL */
-		if (INTEL_INFO(dev)->gen < 9)
-			I915_WRITE(PORT_CLK_SEL(port),
-				   intel_crtc->config->ddi_pll_sel);
-
 		intel_ddi_init_dp_buf_reg(&intel_dig_port->base);
 
 		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
 
-
 		intel_dp_start_link_train(intel_dp);
 		intel_dp_stop_link_train(intel_dp);
 	}
@@ -414,7 +408,10 @@
 {
 #ifdef CONFIG_DRM_FBDEV_EMULATION
 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-	drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper, &connector->base);
+
+	if (dev_priv->fbdev)
+		drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper,
+						&connector->base);
 #endif
 }
 
@@ -422,7 +419,10 @@
 {
 #ifdef CONFIG_DRM_FBDEV_EMULATION
 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-	drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper, &connector->base);
+
+	if (dev_priv->fbdev)
+		drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper,
+						   &connector->base);
 #endif
 }
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 0d00f07..86ce3c2 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -123,8 +123,6 @@
 struct intel_fbdev {
 	struct drm_fb_helper helper;
 	struct intel_framebuffer *fb;
-	struct list_head fbdev_list;
-	struct drm_display_mode *our_mode;
 	int preferred_bpp;
 };
 
@@ -250,6 +248,7 @@
 	unsigned int cdclk;
 	bool dpll_set;
 	struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS];
+	struct intel_wm_config wm_config;
 };
 
 struct intel_plane_state {
@@ -280,6 +279,9 @@
 	int scaler_id;
 
 	struct drm_intel_sprite_colorkey ckey;
+
+	/* async flip related structures */
+	struct drm_i915_gem_request *wait_req;
 };
 
 struct intel_initial_plane_config {
@@ -334,6 +336,21 @@
 /* drm_mode->private_flags */
 #define I915_MODE_FLAG_INHERITED 1
 
+struct intel_pipe_wm {
+	struct intel_wm_level wm[5];
+	uint32_t linetime;
+	bool fbc_wm_enabled;
+	bool pipe_enabled;
+	bool sprites_enabled;
+	bool sprites_scaled;
+};
+
+struct skl_pipe_wm {
+	struct skl_wm_level wm[8];
+	struct skl_wm_level trans_wm;
+	uint32_t linetime;
+};
+
 struct intel_crtc_state {
 	struct drm_crtc_state base;
 
@@ -468,6 +485,20 @@
 
 	/* w/a for waiting 2 vblanks during crtc enable */
 	enum pipe hsw_workaround_pipe;
+
+	/* IVB sprite scaling w/a (WaCxSRDisabledForSpriteScaling:ivb) */
+	bool disable_lp_wm;
+
+	struct {
+		/*
+		 * optimal watermarks, programmed post-vblank when this state
+		 * is committed
+		 */
+		union {
+			struct intel_pipe_wm ilk;
+			struct skl_pipe_wm skl;
+		} optimal;
+	} wm;
 };
 
 struct vlv_wm_state {
@@ -479,26 +510,12 @@
 	bool cxsr;
 };
 
-struct intel_pipe_wm {
-	struct intel_wm_level wm[5];
-	uint32_t linetime;
-	bool fbc_wm_enabled;
-	bool pipe_enabled;
-	bool sprites_enabled;
-	bool sprites_scaled;
-};
-
 struct intel_mmio_flip {
 	struct work_struct work;
 	struct drm_i915_private *i915;
 	struct drm_i915_gem_request *req;
 	struct intel_crtc *crtc;
-};
-
-struct skl_pipe_wm {
-	struct skl_wm_level wm[8];
-	struct skl_wm_level trans_wm;
-	uint32_t linetime;
+	unsigned int rotation;
 };
 
 /*
@@ -509,13 +526,11 @@
  */
 struct intel_crtc_atomic_commit {
 	/* Sleepable operations to perform before commit */
-	bool wait_for_flips;
 	bool disable_fbc;
 	bool disable_ips;
 	bool disable_cxsr;
 	bool pre_disable_primary;
 	bool update_wm_pre, update_wm_post;
-	unsigned disabled_planes;
 
 	/* Sleepable operations to perform after commit */
 	unsigned fb_bits;
@@ -567,9 +582,10 @@
 	/* per-pipe watermark state */
 	struct {
 		/* watermarks currently being used  */
-		struct intel_pipe_wm active;
-		/* SKL wm values currently in use */
-		struct skl_pipe_wm skl_active;
+		union {
+			struct intel_pipe_wm ilk;
+			struct skl_pipe_wm skl;
+		} active;
 		/* allow CxSR on this pipe */
 		bool cxsr_allowed;
 	} wm;
@@ -677,7 +693,7 @@
 #define intel_fb_obj(x) (x ? to_intel_framebuffer(x)->obj : NULL)
 
 struct intel_hdmi {
-	u32 hdmi_reg;
+	i915_reg_t hdmi_reg;
 	int ddc_bus;
 	bool limited_color_range;
 	bool color_range_auto;
@@ -719,15 +735,10 @@
 	M2_N2
 };
 
-struct sink_crc {
-	bool started;
-	u8 last_crc[6];
-	int last_count;
-};
-
 struct intel_dp {
-	uint32_t output_reg;
-	uint32_t aux_ch_ctl_reg;
+	i915_reg_t output_reg;
+	i915_reg_t aux_ch_ctl_reg;
+	i915_reg_t aux_ch_data_reg[5];
 	uint32_t DP;
 	int link_rate;
 	uint8_t lane_count;
@@ -741,7 +752,6 @@
 	/* sink rates as reported by DP_SUPPORTED_LINK_RATES */
 	uint8_t num_sink_rates;
 	int sink_rates[DP_MAX_SUPPORTED_RATES];
-	struct sink_crc sink_crc;
 	struct drm_dp_aux aux;
 	uint8_t train_set[4];
 	int panel_power_up_delay;
@@ -783,6 +793,10 @@
 				     bool has_aux_irq,
 				     int send_bytes,
 				     uint32_t aux_clock_divider);
+
+	/* This is called before a link training is starterd */
+	void (*prepare_link_retrain)(struct intel_dp *intel_dp);
+
 	bool train_set_valid;
 
 	/* Displayport compliance testing */
@@ -799,6 +813,8 @@
 	struct intel_hdmi hdmi;
 	enum irqreturn (*hpd_pulse)(struct intel_digital_port *, bool);
 	bool release_cl2_override;
+	/* for communication with audio component; protected by av_mutex */
+	const struct drm_connector *audio_connector;
 };
 
 struct intel_dp_mst_encoder {
@@ -942,7 +958,8 @@
 					 enum pipe pipe);
 void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
 					 enum transcoder pch_transcoder);
-void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv);
+void intel_check_cpu_fifo_underruns(struct drm_i915_private *dev_priv);
+void intel_check_pch_fifo_underruns(struct drm_i915_private *dev_priv);
 
 /* i915_irq.c */
 void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
@@ -973,6 +990,8 @@
 
 
 /* intel_ddi.c */
+void intel_ddi_clk_select(struct intel_encoder *encoder,
+			  const struct intel_crtc_state *pipe_config);
 void intel_prepare_ddi(struct drm_device *dev);
 void hsw_fdi_link_train(struct drm_crtc *crtc);
 void intel_ddi_init(struct drm_device *dev, enum port port);
@@ -987,7 +1006,7 @@
 bool intel_ddi_pll_select(struct intel_crtc *crtc,
 			  struct intel_crtc_state *crtc_state);
 void intel_ddi_set_pipe_settings(struct drm_crtc *crtc);
-void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder);
+void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp);
 bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
 void intel_ddi_fdi_disable(struct drm_crtc *crtc);
 void intel_ddi_get_config(struct intel_encoder *encoder,
@@ -1055,6 +1074,15 @@
 {
 	drm_wait_one_vblank(dev, pipe);
 }
+static inline void
+intel_wait_for_vblank_if_active(struct drm_device *dev, int pipe)
+{
+	const struct intel_crtc *crtc =
+		to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
+
+	if (crtc->active)
+		intel_wait_for_vblank(dev, pipe);
+}
 int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp);
 void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
 			 struct intel_digital_port *dport,
@@ -1068,9 +1096,7 @@
 				    struct drm_modeset_acquire_ctx *ctx);
 int intel_pin_and_fence_fb_obj(struct drm_plane *plane,
 			       struct drm_framebuffer *fb,
-			       const struct drm_plane_state *plane_state,
-			       struct intel_engine_cs *pipelined,
-			       struct drm_i915_gem_request **pipelined_request);
+			       const struct drm_plane_state *plane_state);
 struct drm_framebuffer *
 __intel_framebuffer_create(struct drm_device *dev,
 			   struct drm_mode_fb_cmd2 *mode_cmd,
@@ -1151,7 +1177,10 @@
 void bxt_enable_dc9(struct drm_i915_private *dev_priv);
 void bxt_disable_dc9(struct drm_i915_private *dev_priv);
 void skl_init_cdclk(struct drm_i915_private *dev_priv);
+int skl_sanitize_cdclk(struct drm_i915_private *dev_priv);
 void skl_uninit_cdclk(struct drm_i915_private *dev_priv);
+void skl_enable_dc6(struct drm_i915_private *dev_priv);
+void skl_disable_dc6(struct drm_i915_private *dev_priv);
 void intel_dp_get_m_n(struct intel_crtc *crtc,
 		      struct intel_crtc_state *pipe_config);
 void intel_dp_set_m_n(struct intel_crtc *crtc, enum link_m_n_set m_n);
@@ -1172,31 +1201,26 @@
 intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder);
 void intel_mode_from_pipe_config(struct drm_display_mode *mode,
 				 struct intel_crtc_state *pipe_config);
-void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);
 void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
 
 int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
 int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state);
 
-unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
-				     struct drm_i915_gem_object *obj,
-				     unsigned int plane);
+u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
+			   struct drm_i915_gem_object *obj,
+			   unsigned int plane);
 
 u32 skl_plane_ctl_format(uint32_t pixel_format);
 u32 skl_plane_ctl_tiling(uint64_t fb_modifier);
 u32 skl_plane_ctl_rotation(unsigned int rotation);
 
 /* intel_csr.c */
-void intel_csr_ucode_init(struct drm_device *dev);
-enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv);
-void intel_csr_load_status_set(struct drm_i915_private *dev_priv,
-					enum csr_state state);
-void intel_csr_load_program(struct drm_device *dev);
-void intel_csr_ucode_fini(struct drm_device *dev);
-void assert_csr_loaded(struct drm_i915_private *dev_priv);
+void intel_csr_ucode_init(struct drm_i915_private *);
+void intel_csr_load_program(struct drm_i915_private *);
+void intel_csr_ucode_fini(struct drm_i915_private *);
 
 /* intel_dp.c */
-void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);
+void intel_dp_init(struct drm_device *dev, i915_reg_t output_reg, enum port port);
 bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 			     struct intel_connector *intel_connector);
 void intel_dp_set_link_params(struct intel_dp *intel_dp,
@@ -1234,6 +1258,22 @@
 					 struct intel_digital_port *port);
 void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config);
 
+void
+intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
+				       uint8_t dp_train_pat);
+void
+intel_dp_set_signal_levels(struct intel_dp *intel_dp);
+void intel_dp_set_idle_link_train(struct intel_dp *intel_dp);
+uint8_t
+intel_dp_voltage_max(struct intel_dp *intel_dp);
+uint8_t
+intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing);
+void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
+			   uint8_t *link_bw, uint8_t *rate_select);
+bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
+bool
+intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]);
+
 /* intel_dp_mst.c */
 int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
 void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port);
@@ -1248,7 +1288,7 @@
 /* legacy fbdev emulation in intel_fbdev.c */
 #ifdef CONFIG_DRM_FBDEV_EMULATION
 extern int intel_fbdev_init(struct drm_device *dev);
-extern void intel_fbdev_initial_config(void *data, async_cookie_t cookie);
+extern void intel_fbdev_initial_config_async(struct drm_device *dev);
 extern void intel_fbdev_fini(struct drm_device *dev);
 extern void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous);
 extern void intel_fbdev_output_poll_changed(struct drm_device *dev);
@@ -1259,7 +1299,7 @@
 	return 0;
 }
 
-static inline void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
+static inline void intel_fbdev_initial_config_async(struct drm_device *dev)
 {
 }
 
@@ -1287,11 +1327,10 @@
 			  enum fb_op_origin origin);
 void intel_fbc_flush(struct drm_i915_private *dev_priv,
 		     unsigned int frontbuffer_bits, enum fb_op_origin origin);
-const char *intel_no_fbc_reason_str(enum no_fbc_reason reason);
 void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv);
 
 /* intel_hdmi.c */
-void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port);
+void intel_hdmi_init(struct drm_device *dev, i915_reg_t hdmi_reg, enum port port);
 void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
 			       struct intel_connector *intel_connector);
 struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
@@ -1367,7 +1406,10 @@
 /* intel_runtime_pm.c */
 int intel_power_domains_init(struct drm_i915_private *);
 void intel_power_domains_fini(struct drm_i915_private *);
-void intel_power_domains_init_hw(struct drm_i915_private *dev_priv);
+void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume);
+void intel_power_domains_suspend(struct drm_i915_private *dev_priv);
+void skl_pw1_misc_io_init(struct drm_i915_private *dev_priv);
+void skl_pw1_misc_io_fini(struct drm_i915_private *dev_priv);
 void intel_runtime_pm_enable(struct drm_i915_private *dev_priv);
 
 bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
@@ -1395,12 +1437,6 @@
 void intel_suspend_hw(struct drm_device *dev);
 int ilk_wm_max_level(const struct drm_device *dev);
 void intel_update_watermarks(struct drm_crtc *crtc);
-void intel_update_sprite_watermarks(struct drm_plane *plane,
-				    struct drm_crtc *crtc,
-				    uint32_t sprite_width,
-				    uint32_t sprite_height,
-				    int pixel_size,
-				    bool enabled, bool scaled);
 void intel_init_pm(struct drm_device *dev);
 void intel_pm_setup(struct drm_device *dev);
 void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
@@ -1428,7 +1464,8 @@
 uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
 
 /* intel_sdvo.c */
-bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob);
+bool intel_sdvo_init(struct drm_device *dev,
+		     i915_reg_t reg, enum port port);
 
 
 /* intel_sprite.c */
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
index 170ae6f..efb5a27 100644
--- a/drivers/gpu/drm/i915/intel_dsi.c
+++ b/drivers/gpu/drm/i915/intel_dsi.c
@@ -60,7 +60,8 @@
 		DRM_ERROR("DPI FIFOs are not empty\n");
 }
 
-static void write_data(struct drm_i915_private *dev_priv, u32 reg,
+static void write_data(struct drm_i915_private *dev_priv,
+		       i915_reg_t reg,
 		       const u8 *data, u32 len)
 {
 	u32 i, j;
@@ -75,7 +76,8 @@
 	}
 }
 
-static void read_data(struct drm_i915_private *dev_priv, u32 reg,
+static void read_data(struct drm_i915_private *dev_priv,
+		      i915_reg_t reg,
 		      u8 *data, u32 len)
 {
 	u32 i, j;
@@ -98,7 +100,8 @@
 	struct mipi_dsi_packet packet;
 	ssize_t ret;
 	const u8 *header, *data;
-	u32 data_reg, data_mask, ctrl_reg, ctrl_mask;
+	i915_reg_t data_reg, ctrl_reg;
+	u32 data_mask, ctrl_mask;
 
 	ret = mipi_dsi_create_packet(&packet, msg);
 	if (ret < 0)
@@ -377,10 +380,10 @@
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
 	enum port port;
-	u32 temp;
-	u32 port_ctrl;
 
 	if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
+		u32 temp;
+
 		temp = I915_READ(VLV_CHICKEN_3);
 		temp &= ~PIXEL_OVERLAP_CNT_MASK |
 					intel_dsi->pixel_overlap <<
@@ -389,8 +392,9 @@
 	}
 
 	for_each_dsi_port(port, intel_dsi->ports) {
-		port_ctrl = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) :
-						MIPI_PORT_CTRL(port);
+		i915_reg_t port_ctrl = IS_BROXTON(dev) ?
+			BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port);
+		u32 temp;
 
 		temp = I915_READ(port_ctrl);
 
@@ -416,13 +420,13 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
 	enum port port;
-	u32 temp;
-	u32 port_ctrl;
 
 	for_each_dsi_port(port, intel_dsi->ports) {
+		i915_reg_t port_ctrl = IS_BROXTON(dev) ?
+			BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port);
+		u32 temp;
+
 		/* de-assert ip_tg_enable signal */
-		port_ctrl = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) :
-						MIPI_PORT_CTRL(port);
 		temp = I915_READ(port_ctrl);
 		I915_WRITE(port_ctrl, temp & ~DPI_ENABLE);
 		POSTING_READ(port_ctrl);
@@ -580,11 +584,13 @@
 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
 	enum port port;
-	u32 val;
-	u32 port_ctrl = 0;
 
 	DRM_DEBUG_KMS("\n");
 	for_each_dsi_port(port, intel_dsi->ports) {
+		/* Common bit for both MIPI Port A & MIPI Port C on VLV/CHV */
+		i915_reg_t port_ctrl = IS_BROXTON(dev) ?
+			BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(PORT_A);
+		u32 val;
 
 		I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
 							ULPS_STATE_ENTER);
@@ -598,12 +604,6 @@
 							ULPS_STATE_ENTER);
 		usleep_range(2000, 2500);
 
-		if (IS_BROXTON(dev))
-			port_ctrl = BXT_MIPI_PORT_CTRL(port);
-		else if (IS_VALLEYVIEW(dev))
-			/* Common bit for both MIPI Port A & MIPI Port C */
-			port_ctrl = MIPI_PORT_CTRL(PORT_A);
-
 		/* Wait till Clock lanes are in LP-00 state for MIPI Port A
 		 * only. MIPI Port C has no similar bit for checking
 		 */
@@ -656,7 +656,6 @@
 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
 	struct drm_device *dev = encoder->base.dev;
 	enum intel_display_power_domain power_domain;
-	u32 dpi_enabled, func, ctrl_reg;
 	enum port port;
 
 	DRM_DEBUG_KMS("\n");
@@ -667,9 +666,11 @@
 
 	/* XXX: this only works for one DSI output */
 	for_each_dsi_port(port, intel_dsi->ports) {
+		i915_reg_t ctrl_reg = IS_BROXTON(dev) ?
+			BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port);
+		u32 dpi_enabled, func;
+
 		func = I915_READ(MIPI_DSI_FUNC_PRG(port));
-		ctrl_reg = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) :
-						MIPI_PORT_CTRL(port);
 		dpi_enabled = I915_READ(ctrl_reg) & DPI_ENABLE;
 
 		/* Due to some hardware limitations on BYT, MIPI Port C DPI
diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h
index e6cb252..02551ff 100644
--- a/drivers/gpu/drm/i915/intel_dsi.h
+++ b/drivers/gpu/drm/i915/intel_dsi.h
@@ -117,7 +117,7 @@
 
 #define for_each_dsi_port(__port, __ports_mask) \
 	for ((__port) = PORT_A; (__port) < I915_MAX_PORTS; (__port)++)	\
-		if ((__ports_mask) & (1 << (__port)))
+		for_each_if ((__ports_mask) & (1 << (__port)))
 
 static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
 {
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index 8492053..7161deb 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -44,6 +44,7 @@
 		.type = INTEL_DVO_CHIP_TMDS,
 		.name = "sil164",
 		.dvo_reg = DVOC,
+		.dvo_srcdim_reg = DVOC_SRCDIM,
 		.slave_addr = SIL164_ADDR,
 		.dev_ops = &sil164_ops,
 	},
@@ -51,6 +52,7 @@
 		.type = INTEL_DVO_CHIP_TMDS,
 		.name = "ch7xxx",
 		.dvo_reg = DVOC,
+		.dvo_srcdim_reg = DVOC_SRCDIM,
 		.slave_addr = CH7xxx_ADDR,
 		.dev_ops = &ch7xxx_ops,
 	},
@@ -58,6 +60,7 @@
 		.type = INTEL_DVO_CHIP_TMDS,
 		.name = "ch7xxx",
 		.dvo_reg = DVOC,
+		.dvo_srcdim_reg = DVOC_SRCDIM,
 		.slave_addr = 0x75, /* For some ch7010 */
 		.dev_ops = &ch7xxx_ops,
 	},
@@ -65,6 +68,7 @@
 		.type = INTEL_DVO_CHIP_LVDS,
 		.name = "ivch",
 		.dvo_reg = DVOA,
+		.dvo_srcdim_reg = DVOA_SRCDIM,
 		.slave_addr = 0x02, /* Might also be 0x44, 0x84, 0xc4 */
 		.dev_ops = &ivch_ops,
 	},
@@ -72,6 +76,7 @@
 		.type = INTEL_DVO_CHIP_TMDS,
 		.name = "tfp410",
 		.dvo_reg = DVOC,
+		.dvo_srcdim_reg = DVOC_SRCDIM,
 		.slave_addr = TFP410_ADDR,
 		.dev_ops = &tfp410_ops,
 	},
@@ -79,6 +84,7 @@
 		.type = INTEL_DVO_CHIP_LVDS,
 		.name = "ch7017",
 		.dvo_reg = DVOC,
+		.dvo_srcdim_reg = DVOC_SRCDIM,
 		.slave_addr = 0x75,
 		.gpio = GMBUS_PIN_DPB,
 		.dev_ops = &ch7017_ops,
@@ -87,6 +93,7 @@
 	        .type = INTEL_DVO_CHIP_TMDS,
 		.name = "ns2501",
 		.dvo_reg = DVOB,
+		.dvo_srcdim_reg = DVOB_SRCDIM,
 		.slave_addr = NS2501_ADDR,
 		.dev_ops = &ns2501_ops,
        }
@@ -171,7 +178,7 @@
 {
 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
 	struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
-	u32 dvo_reg = intel_dvo->dev.dvo_reg;
+	i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
 	u32 temp = I915_READ(dvo_reg);
 
 	intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
@@ -184,7 +191,7 @@
 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
 	struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
-	u32 dvo_reg = intel_dvo->dev.dvo_reg;
+	i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
 	u32 temp = I915_READ(dvo_reg);
 
 	intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
@@ -255,20 +262,8 @@
 	struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
 	int pipe = crtc->pipe;
 	u32 dvo_val;
-	u32 dvo_reg = intel_dvo->dev.dvo_reg, dvo_srcdim_reg;
-
-	switch (dvo_reg) {
-	case DVOA:
-	default:
-		dvo_srcdim_reg = DVOA_SRCDIM;
-		break;
-	case DVOB:
-		dvo_srcdim_reg = DVOB_SRCDIM;
-		break;
-	case DVOC:
-		dvo_srcdim_reg = DVOC_SRCDIM;
-		break;
-	}
+	i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
+	i915_reg_t dvo_srcdim_reg = intel_dvo->dev.dvo_srcdim_reg;
 
 	/* Save the data order, since I don't know what it should be set to. */
 	dvo_val = I915_READ(dvo_reg) &
diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c
index cf47352..11fc528 100644
--- a/drivers/gpu/drm/i915/intel_fbc.c
+++ b/drivers/gpu/drm/i915/intel_fbc.c
@@ -46,6 +46,11 @@
 	return dev_priv->fbc.enable_fbc != NULL;
 }
 
+static inline bool fbc_on_pipe_a_only(struct drm_i915_private *dev_priv)
+{
+	return IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8;
+}
+
 /*
  * In some platforms where the CRTC's x:0/y:0 coordinates doesn't match the
  * frontbuffer's x:0/y:0 coordinates we lie to the hardware about the plane's
@@ -182,7 +187,8 @@
 	return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
 }
 
-static void intel_fbc_nuke(struct drm_i915_private *dev_priv)
+/* This function forces a CFB recompression through the nuke operation. */
+static void intel_fbc_recompress(struct drm_i915_private *dev_priv)
 {
 	I915_WRITE(MSG_FBC_REND_STATE, FBC_REND_NUKE);
 	POSTING_READ(MSG_FBC_REND_STATE);
@@ -231,7 +237,7 @@
 		I915_WRITE(DPFC_CPU_FENCE_OFFSET, y_offset);
 	}
 
-	intel_fbc_nuke(dev_priv);
+	intel_fbc_recompress(dev_priv);
 
 	DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(crtc->plane));
 }
@@ -310,7 +316,7 @@
 		   SNB_CPU_FENCE_ENABLE | obj->fence_reg);
 	I915_WRITE(DPFC_CPU_FENCE_OFFSET, get_crtc_fence_y_offset(crtc));
 
-	intel_fbc_nuke(dev_priv);
+	intel_fbc_recompress(dev_priv);
 
 	DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(crtc->plane));
 }
@@ -370,8 +376,6 @@
 	if (dev_priv->fbc.fbc_work == NULL)
 		return;
 
-	DRM_DEBUG_KMS("cancelling pending FBC enable\n");
-
 	/* Synchronisation is provided by struct_mutex and checking of
 	 * dev_priv->fbc.fbc_work, so we can perform the cancellation
 	 * entirely asynchronously.
@@ -432,7 +436,8 @@
 
 	intel_fbc_cancel_work(dev_priv);
 
-	dev_priv->fbc.disable_fbc(dev_priv);
+	if (dev_priv->fbc.enabled)
+		dev_priv->fbc.disable_fbc(dev_priv);
 	dev_priv->fbc.crtc = NULL;
 }
 
@@ -471,78 +476,45 @@
 	mutex_unlock(&dev_priv->fbc.lock);
 }
 
-const char *intel_no_fbc_reason_str(enum no_fbc_reason reason)
-{
-	switch (reason) {
-	case FBC_OK:
-		return "FBC enabled but currently disabled in hardware";
-	case FBC_UNSUPPORTED:
-		return "unsupported by this chipset";
-	case FBC_NO_OUTPUT:
-		return "no output";
-	case FBC_STOLEN_TOO_SMALL:
-		return "not enough stolen memory";
-	case FBC_UNSUPPORTED_MODE:
-		return "mode incompatible with compression";
-	case FBC_MODE_TOO_LARGE:
-		return "mode too large for compression";
-	case FBC_BAD_PLANE:
-		return "FBC unsupported on plane";
-	case FBC_NOT_TILED:
-		return "framebuffer not tiled or fenced";
-	case FBC_MULTIPLE_PIPES:
-		return "more than one pipe active";
-	case FBC_MODULE_PARAM:
-		return "disabled per module param";
-	case FBC_CHIP_DEFAULT:
-		return "disabled per chip default";
-	case FBC_ROTATION:
-		return "rotation unsupported";
-	case FBC_IN_DBG_MASTER:
-		return "Kernel debugger is active";
-	case FBC_BAD_STRIDE:
-		return "framebuffer stride not supported";
-	case FBC_PIXEL_RATE:
-		return "pixel rate is too big";
-	case FBC_PIXEL_FORMAT:
-		return "pixel format is invalid";
-	default:
-		MISSING_CASE(reason);
-		return "unknown reason";
-	}
-}
-
 static void set_no_fbc_reason(struct drm_i915_private *dev_priv,
-			      enum no_fbc_reason reason)
+			      const char *reason)
 {
 	if (dev_priv->fbc.no_fbc_reason == reason)
 		return;
 
 	dev_priv->fbc.no_fbc_reason = reason;
-	DRM_DEBUG_KMS("Disabling FBC: %s\n", intel_no_fbc_reason_str(reason));
+	DRM_DEBUG_KMS("Disabling FBC: %s\n", reason);
+}
+
+static bool crtc_is_valid(struct intel_crtc *crtc)
+{
+	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
+	if (fbc_on_pipe_a_only(dev_priv) && crtc->pipe != PIPE_A)
+		return false;
+
+	if (!intel_crtc_active(&crtc->base))
+		return false;
+
+	if (!to_intel_plane_state(crtc->base.primary->state)->visible)
+		return false;
+
+	return true;
 }
 
 static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv)
 {
 	struct drm_crtc *crtc = NULL, *tmp_crtc;
 	enum pipe pipe;
-	bool pipe_a_only = false;
-
-	if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8)
-		pipe_a_only = true;
 
 	for_each_pipe(dev_priv, pipe) {
 		tmp_crtc = dev_priv->pipe_to_crtc_mapping[pipe];
 
-		if (intel_crtc_active(tmp_crtc) &&
-		    to_intel_plane_state(tmp_crtc->primary->state)->visible)
+		if (crtc_is_valid(to_intel_crtc(tmp_crtc)))
 			crtc = tmp_crtc;
-
-		if (pipe_a_only)
-			break;
 	}
 
-	if (!crtc || crtc->primary->fb == NULL)
+	if (!crtc)
 		return NULL;
 
 	return crtc;
@@ -581,7 +553,8 @@
 	 * reserved range size, so it always assumes the maximum (8mb) is used.
 	 * If we enable FBC using a CFB on that memory range we'll get FIFO
 	 * underruns, even if that range is not reserved by the BIOS. */
-	if (IS_BROADWELL(dev_priv) || IS_SKYLAKE(dev_priv))
+	if (IS_BROADWELL(dev_priv) ||
+	    IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
 		end = dev_priv->gtt.stolen_size - 8 * 1024 * 1024;
 	else
 		end = dev_priv->gtt.stolen_usable_size;
@@ -734,6 +707,7 @@
 	if (INTEL_INFO(dev_priv)->gen >= 7)
 		lines = min(lines, 2048);
 
+	/* Hardware needs the full buffer stride, not just the active area. */
 	return lines * fb->pitches[0];
 }
 
@@ -832,84 +806,62 @@
  * __intel_fbc_update - enable/disable FBC as needed, unlocked
  * @dev_priv: i915 device instance
  *
- * Set up the framebuffer compression hardware at mode set time.  We
- * enable it if possible:
- *   - plane A only (on pre-965)
- *   - no pixel mulitply/line duplication
- *   - no alpha buffer discard
- *   - no dual wide
- *   - framebuffer <= max_hdisplay in width, max_vdisplay in height
- *
- * We can't assume that any compression will take place (worst case),
- * so the compressed buffer has to be the same size as the uncompressed
- * one.  It also must reside (along with the line length buffer) in
- * stolen memory.
- *
- * We need to enable/disable FBC on a global basis.
+ * This function completely reevaluates the status of FBC, then enables,
+ * disables or maintains it on the same state.
  */
 static void __intel_fbc_update(struct drm_i915_private *dev_priv)
 {
-	struct drm_crtc *crtc = NULL;
-	struct intel_crtc *intel_crtc;
+	struct drm_crtc *drm_crtc = NULL;
+	struct intel_crtc *crtc;
 	struct drm_framebuffer *fb;
 	struct drm_i915_gem_object *obj;
 	const struct drm_display_mode *adjusted_mode;
 
 	WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock));
 
-	/* disable framebuffer compression in vGPU */
 	if (intel_vgpu_active(dev_priv->dev))
 		i915.enable_fbc = 0;
 
 	if (i915.enable_fbc < 0) {
-		set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT);
+		set_no_fbc_reason(dev_priv, "disabled per chip default");
 		goto out_disable;
 	}
 
 	if (!i915.enable_fbc) {
-		set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM);
+		set_no_fbc_reason(dev_priv, "disabled per module param");
 		goto out_disable;
 	}
 
-	/*
-	 * If FBC is already on, we just have to verify that we can
-	 * keep it that way...
-	 * Need to disable if:
-	 *   - more than one pipe is active
-	 *   - changing FBC params (stride, fence, mode)
-	 *   - new fb is too large to fit in compressed buffer
-	 *   - going to an unsupported config (interlace, pixel multiply, etc.)
-	 */
-	crtc = intel_fbc_find_crtc(dev_priv);
-	if (!crtc) {
-		set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT);
+	drm_crtc = intel_fbc_find_crtc(dev_priv);
+	if (!drm_crtc) {
+		set_no_fbc_reason(dev_priv, "no output");
 		goto out_disable;
 	}
 
 	if (!multiple_pipes_ok(dev_priv)) {
-		set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES);
+		set_no_fbc_reason(dev_priv, "more than one pipe active");
 		goto out_disable;
 	}
 
-	intel_crtc = to_intel_crtc(crtc);
-	fb = crtc->primary->fb;
+	crtc = to_intel_crtc(drm_crtc);
+	fb = crtc->base.primary->fb;
 	obj = intel_fb_obj(fb);
-	adjusted_mode = &intel_crtc->config->base.adjusted_mode;
+	adjusted_mode = &crtc->config->base.adjusted_mode;
 
 	if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ||
 	    (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
-		set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE);
+		set_no_fbc_reason(dev_priv, "incompatible mode");
 		goto out_disable;
 	}
 
-	if (!intel_fbc_hw_tracking_covers_screen(intel_crtc)) {
-		set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE);
+	if (!intel_fbc_hw_tracking_covers_screen(crtc)) {
+		set_no_fbc_reason(dev_priv, "mode too large for compression");
 		goto out_disable;
 	}
 
 	if ((INTEL_INFO(dev_priv)->gen < 4 || HAS_DDI(dev_priv)) &&
-	    intel_crtc->plane != PLANE_A) {
-		set_no_fbc_reason(dev_priv, FBC_BAD_PLANE);
+	    crtc->plane != PLANE_A) {
+		set_no_fbc_reason(dev_priv, "FBC unsupported on plane");
 		goto out_disable;
 	}
 
@@ -918,41 +870,35 @@
 	 */
 	if (obj->tiling_mode != I915_TILING_X ||
 	    obj->fence_reg == I915_FENCE_REG_NONE) {
-		set_no_fbc_reason(dev_priv, FBC_NOT_TILED);
+		set_no_fbc_reason(dev_priv, "framebuffer not tiled or fenced");
 		goto out_disable;
 	}
 	if (INTEL_INFO(dev_priv)->gen <= 4 && !IS_G4X(dev_priv) &&
-	    crtc->primary->state->rotation != BIT(DRM_ROTATE_0)) {
-		set_no_fbc_reason(dev_priv, FBC_ROTATION);
+	    crtc->base.primary->state->rotation != BIT(DRM_ROTATE_0)) {
+		set_no_fbc_reason(dev_priv, "rotation unsupported");
 		goto out_disable;
 	}
 
 	if (!stride_is_valid(dev_priv, fb->pitches[0])) {
-		set_no_fbc_reason(dev_priv, FBC_BAD_STRIDE);
+		set_no_fbc_reason(dev_priv, "framebuffer stride not supported");
 		goto out_disable;
 	}
 
 	if (!pixel_format_is_valid(fb)) {
-		set_no_fbc_reason(dev_priv, FBC_PIXEL_FORMAT);
-		goto out_disable;
-	}
-
-	/* If the kernel debugger is active, always disable compression */
-	if (in_dbg_master()) {
-		set_no_fbc_reason(dev_priv, FBC_IN_DBG_MASTER);
+		set_no_fbc_reason(dev_priv, "pixel format is invalid");
 		goto out_disable;
 	}
 
 	/* WaFbcExceedCdClockThreshold:hsw,bdw */
 	if ((IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) &&
-	    ilk_pipe_pixel_rate(intel_crtc->config) >=
+	    ilk_pipe_pixel_rate(crtc->config) >=
 	    dev_priv->cdclk_freq * 95 / 100) {
-		set_no_fbc_reason(dev_priv, FBC_PIXEL_RATE);
+		set_no_fbc_reason(dev_priv, "pixel rate is too big");
 		goto out_disable;
 	}
 
-	if (intel_fbc_setup_cfb(intel_crtc)) {
-		set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL);
+	if (intel_fbc_setup_cfb(crtc)) {
+		set_no_fbc_reason(dev_priv, "not enough stolen memory");
 		goto out_disable;
 	}
 
@@ -961,9 +907,9 @@
 	 * cannot be unpinned (and have its GTT offset and fence revoked)
 	 * without first being decoupled from the scanout and FBC disabled.
 	 */
-	if (dev_priv->fbc.crtc == intel_crtc &&
+	if (dev_priv->fbc.crtc == crtc &&
 	    dev_priv->fbc.fb_id == fb->base.id &&
-	    dev_priv->fbc.y == crtc->y)
+	    dev_priv->fbc.y == crtc->base.y)
 		return;
 
 	if (intel_fbc_enabled(dev_priv)) {
@@ -994,8 +940,8 @@
 		__intel_fbc_disable(dev_priv);
 	}
 
-	intel_fbc_schedule_enable(intel_crtc);
-	dev_priv->fbc.no_fbc_reason = FBC_OK;
+	intel_fbc_schedule_enable(crtc);
+	dev_priv->fbc.no_fbc_reason = "FBC enabled (not necessarily active)";
 	return;
 
 out_disable:
@@ -1085,10 +1031,10 @@
 	enum pipe pipe;
 
 	mutex_init(&dev_priv->fbc.lock);
+	dev_priv->fbc.enabled = false;
 
 	if (!HAS_FBC(dev_priv)) {
-		dev_priv->fbc.enabled = false;
-		dev_priv->fbc.no_fbc_reason = FBC_UNSUPPORTED;
+		dev_priv->fbc.no_fbc_reason = "unsupported by this chipset";
 		return;
 	}
 
@@ -1096,7 +1042,7 @@
 		dev_priv->fbc.possible_framebuffer_bits |=
 				INTEL_FRONTBUFFER_PRIMARY(pipe);
 
-		if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8)
+		if (fbc_on_pipe_a_only(dev_priv))
 			break;
 	}
 
@@ -1121,5 +1067,9 @@
 		I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT);
 	}
 
-	dev_priv->fbc.enabled = dev_priv->fbc.fbc_enabled(dev_priv);
+	/* We still don't have any sort of hardware state readout for FBC, so
+	 * disable it in case the BIOS enabled it to make sure software matches
+	 * the hardware state. */
+	if (dev_priv->fbc.fbc_enabled(dev_priv))
+		dev_priv->fbc.disable_fbc(dev_priv);
 }
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 4fd5fdf..7ccde58 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -119,7 +119,7 @@
 {
 	struct intel_fbdev *ifbdev =
 		container_of(helper, struct intel_fbdev, helper);
-	struct drm_framebuffer *fb;
+	struct drm_framebuffer *fb = NULL;
 	struct drm_device *dev = helper->dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	struct drm_mode_fb_cmd2 mode_cmd = {};
@@ -138,6 +138,8 @@
 	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
 							  sizes->surface_depth);
 
+	mutex_lock(&dev->struct_mutex);
+
 	size = mode_cmd.pitches[0] * mode_cmd.height;
 	size = PAGE_ALIGN(size);
 
@@ -156,26 +158,28 @@
 
 	fb = __intel_framebuffer_create(dev, &mode_cmd, obj);
 	if (IS_ERR(fb)) {
+		drm_gem_object_unreference(&obj->base);
 		ret = PTR_ERR(fb);
-		goto out_unref;
+		goto out;
 	}
 
 	/* Flush everything out, we'll be doing GTT only from now on */
-	ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL, NULL, NULL);
+	ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL);
 	if (ret) {
 		DRM_ERROR("failed to pin obj: %d\n", ret);
-		goto out_fb;
+		goto out;
 	}
 
+	mutex_unlock(&dev->struct_mutex);
+
 	ifbdev->fb = to_intel_framebuffer(fb);
 
 	return 0;
 
-out_fb:
-	drm_framebuffer_remove(fb);
-out_unref:
-	drm_gem_object_unreference(&obj->base);
 out:
+	mutex_unlock(&dev->struct_mutex);
+	if (!IS_ERR_OR_NULL(fb))
+		drm_framebuffer_unreference(fb);
 	return ret;
 }
 
@@ -193,8 +197,6 @@
 	int size, ret;
 	bool prealloc = false;
 
-	mutex_lock(&dev->struct_mutex);
-
 	if (intel_fb &&
 	    (sizes->fb_width > intel_fb->base.width ||
 	     sizes->fb_height > intel_fb->base.height)) {
@@ -209,7 +211,7 @@
 		DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n");
 		ret = intelfb_alloc(helper, sizes);
 		if (ret)
-			goto out_unlock;
+			return ret;
 		intel_fb = ifbdev->fb;
 	} else {
 		DRM_DEBUG_KMS("re-using BIOS fb\n");
@@ -221,8 +223,11 @@
 	obj = intel_fb->obj;
 	size = obj->base.size;
 
+	mutex_lock(&dev->struct_mutex);
+
 	info = drm_fb_helper_alloc_fbi(helper);
 	if (IS_ERR(info)) {
+		DRM_ERROR("Failed to allocate fb_info\n");
 		ret = PTR_ERR(info);
 		goto out_unpin;
 	}
@@ -249,6 +254,7 @@
 		ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj),
 			   size);
 	if (!info->screen_base) {
+		DRM_ERROR("Failed to remap framebuffer into virtual memory\n");
 		ret = -ENOSPC;
 		goto out_destroy_fbi;
 	}
@@ -281,8 +287,6 @@
 	drm_fb_helper_release_fbi(helper);
 out_unpin:
 	i915_gem_object_ggtt_unpin(obj);
-	drm_gem_object_unreference(&obj->base);
-out_unlock:
 	mutex_unlock(&dev->struct_mutex);
 	return ret;
 }
@@ -526,8 +530,10 @@
 
 	drm_fb_helper_fini(&ifbdev->helper);
 
-	drm_framebuffer_unregister_private(&ifbdev->fb->base);
-	drm_framebuffer_remove(&ifbdev->fb->base);
+	if (ifbdev->fb) {
+		drm_framebuffer_unregister_private(&ifbdev->fb->base);
+		drm_framebuffer_remove(&ifbdev->fb->base);
+	}
 }
 
 /*
@@ -702,13 +708,20 @@
 	return 0;
 }
 
-void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
+static void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
 {
 	struct drm_i915_private *dev_priv = data;
 	struct intel_fbdev *ifbdev = dev_priv->fbdev;
 
 	/* Due to peculiar init order wrt to hpd handling this is separate. */
-	drm_fb_helper_initial_config(&ifbdev->helper, ifbdev->preferred_bpp);
+	if (drm_fb_helper_initial_config(&ifbdev->helper,
+					 ifbdev->preferred_bpp))
+		intel_fbdev_fini(dev_priv->dev);
+}
+
+void intel_fbdev_initial_config_async(struct drm_device *dev)
+{
+	async_schedule(intel_fbdev_initial_config, to_i915(dev));
 }
 
 void intel_fbdev_fini(struct drm_device *dev)
@@ -719,7 +732,8 @@
 
 	flush_work(&dev_priv->fbdev_suspend_work);
 
-	async_synchronize_full();
+	if (!current_is_async())
+		async_synchronize_full();
 	intel_fbdev_destroy(dev, dev_priv->fbdev);
 	kfree(dev_priv->fbdev);
 	dev_priv->fbdev = NULL;
diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c
index 54daa66..7ae182d 100644
--- a/drivers/gpu/drm/i915/intel_fifo_underrun.c
+++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c
@@ -84,38 +84,21 @@
 	return true;
 }
 
-/**
- * i9xx_check_fifo_underruns - check for fifo underruns
- * @dev_priv: i915 device instance
- *
- * This function checks for fifo underruns on GMCH platforms. This needs to be
- * done manually on modeset to make sure that we catch all underruns since they
- * do not generate an interrupt by themselves on these platforms.
- */
-void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv)
+static void i9xx_check_fifo_underruns(struct intel_crtc *crtc)
 {
-	struct intel_crtc *crtc;
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	i915_reg_t reg = PIPESTAT(crtc->pipe);
+	u32 pipestat = I915_READ(reg) & 0xffff0000;
 
-	spin_lock_irq(&dev_priv->irq_lock);
+	assert_spin_locked(&dev_priv->irq_lock);
 
-	for_each_intel_crtc(dev_priv->dev, crtc) {
-		u32 reg = PIPESTAT(crtc->pipe);
-		u32 pipestat;
+	if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0)
+		return;
 
-		if (crtc->cpu_fifo_underrun_disabled)
-			continue;
+	I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
+	POSTING_READ(reg);
 
-		pipestat = I915_READ(reg) & 0xffff0000;
-		if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0)
-			continue;
-
-		I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
-		POSTING_READ(reg);
-
-		DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe));
-	}
-
-	spin_unlock_irq(&dev_priv->irq_lock);
+	DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe));
 }
 
 static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev,
@@ -123,7 +106,7 @@
 					     bool enable, bool old)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 reg = PIPESTAT(pipe);
+	i915_reg_t reg = PIPESTAT(pipe);
 	u32 pipestat = I915_READ(reg) & 0xffff0000;
 
 	assert_spin_locked(&dev_priv->irq_lock);
@@ -150,6 +133,23 @@
 		ironlake_disable_display_irq(dev_priv, bit);
 }
 
+static void ivybridge_check_fifo_underruns(struct intel_crtc *crtc)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	enum pipe pipe = crtc->pipe;
+	uint32_t err_int = I915_READ(GEN7_ERR_INT);
+
+	assert_spin_locked(&dev_priv->irq_lock);
+
+	if ((err_int & ERR_INT_FIFO_UNDERRUN(pipe)) == 0)
+		return;
+
+	I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe));
+	POSTING_READ(GEN7_ERR_INT);
+
+	DRM_ERROR("fifo underrun on pipe %c\n", pipe_name(pipe));
+}
+
 static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
 						  enum pipe pipe,
 						  bool enable, bool old)
@@ -202,6 +202,24 @@
 		ibx_disable_display_interrupt(dev_priv, bit);
 }
 
+static void cpt_check_pch_fifo_underruns(struct intel_crtc *crtc)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	enum transcoder pch_transcoder = (enum transcoder) crtc->pipe;
+	uint32_t serr_int = I915_READ(SERR_INT);
+
+	assert_spin_locked(&dev_priv->irq_lock);
+
+	if ((serr_int & SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) == 0)
+		return;
+
+	I915_WRITE(SERR_INT, SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder));
+	POSTING_READ(SERR_INT);
+
+	DRM_ERROR("pch fifo underrun on pch transcoder %c\n",
+		  transcoder_name(pch_transcoder));
+}
+
 static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
 					    enum transcoder pch_transcoder,
 					    bool enable, bool old)
@@ -375,3 +393,56 @@
 		DRM_ERROR("PCH transcoder %c FIFO underrun\n",
 			  transcoder_name(pch_transcoder));
 }
+
+/**
+ * intel_check_cpu_fifo_underruns - check for CPU fifo underruns immediately
+ * @dev_priv: i915 device instance
+ *
+ * Check for CPU fifo underruns immediately. Useful on IVB/HSW where the shared
+ * error interrupt may have been disabled, and so CPU fifo underruns won't
+ * necessarily raise an interrupt, and on GMCH platforms where underruns never
+ * raise an interrupt.
+ */
+void intel_check_cpu_fifo_underruns(struct drm_i915_private *dev_priv)
+{
+	struct intel_crtc *crtc;
+
+	spin_lock_irq(&dev_priv->irq_lock);
+
+	for_each_intel_crtc(dev_priv->dev, crtc) {
+		if (crtc->cpu_fifo_underrun_disabled)
+			continue;
+
+		if (HAS_GMCH_DISPLAY(dev_priv))
+			i9xx_check_fifo_underruns(crtc);
+		else if (IS_GEN7(dev_priv))
+			ivybridge_check_fifo_underruns(crtc);
+	}
+
+	spin_unlock_irq(&dev_priv->irq_lock);
+}
+
+/**
+ * intel_check_pch_fifo_underruns - check for PCH fifo underruns immediately
+ * @dev_priv: i915 device instance
+ *
+ * Check for PCH fifo underruns immediately. Useful on CPT/PPT where the shared
+ * error interrupt may have been disabled, and so PCH fifo underruns won't
+ * necessarily raise an interrupt.
+ */
+void intel_check_pch_fifo_underruns(struct drm_i915_private *dev_priv)
+{
+	struct intel_crtc *crtc;
+
+	spin_lock_irq(&dev_priv->irq_lock);
+
+	for_each_intel_crtc(dev_priv->dev, crtc) {
+		if (crtc->pch_fifo_underrun_disabled)
+			continue;
+
+		if (HAS_PCH_CPT(dev_priv))
+			cpt_check_pch_fifo_underruns(crtc);
+	}
+
+	spin_unlock_irq(&dev_priv->irq_lock);
+}
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 081d5f6..5ba5866 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -76,11 +76,17 @@
 	uint16_t			guc_fw_minor_wanted;
 	uint16_t			guc_fw_major_found;
 	uint16_t			guc_fw_minor_found;
+
+	uint32_t header_size;
+	uint32_t header_offset;
+	uint32_t rsa_size;
+	uint32_t rsa_offset;
+	uint32_t ucode_size;
+	uint32_t ucode_offset;
 };
 
 struct intel_guc {
 	struct intel_guc_fw guc_fw;
-
 	uint32_t log_flags;
 	struct drm_i915_gem_object *log_obj;
 
diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h
index 593d2f5..40b2ea5 100644
--- a/drivers/gpu/drm/i915/intel_guc_fwif.h
+++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
@@ -122,6 +122,78 @@
 
 #define GUC_CTL_MAX_DWORDS		(GUC_CTL_RSRVD + 1)
 
+/**
+ * DOC: GuC Firmware Layout
+ *
+ * The GuC firmware layout looks like this:
+ *
+ *     +-------------------------------+
+ *     |        guc_css_header         |
+ *     | contains major/minor version  |
+ *     +-------------------------------+
+ *     |             uCode             |
+ *     +-------------------------------+
+ *     |         RSA signature         |
+ *     +-------------------------------+
+ *     |          modulus key          |
+ *     +-------------------------------+
+ *     |          exponent val         |
+ *     +-------------------------------+
+ *
+ * The firmware may or may not have modulus key and exponent data. The header,
+ * uCode and RSA signature are must-have components that will be used by driver.
+ * Length of each components, which is all in dwords, can be found in header.
+ * In the case that modulus and exponent are not present in fw, a.k.a truncated
+ * image, the length value still appears in header.
+ *
+ * Driver will do some basic fw size validation based on the following rules:
+ *
+ * 1. Header, uCode and RSA are must-have components.
+ * 2. All firmware components, if they present, are in the sequence illustrated
+ * in the layout table above.
+ * 3. Length info of each component can be found in header, in dwords.
+ * 4. Modulus and exponent key are not required by driver. They may not appear
+ * in fw. So driver will load a truncated firmware in this case.
+ */
+
+struct guc_css_header {
+	uint32_t module_type;
+	/* header_size includes all non-uCode bits, including css_header, rsa
+	 * key, modulus key and exponent data. */
+	uint32_t header_size_dw;
+	uint32_t header_version;
+	uint32_t module_id;
+	uint32_t module_vendor;
+	union {
+		struct {
+			uint8_t day;
+			uint8_t month;
+			uint16_t year;
+		};
+		uint32_t date;
+	};
+	uint32_t size_dw; /* uCode plus header_size_dw */
+	uint32_t key_size_dw;
+	uint32_t modulus_size_dw;
+	uint32_t exponent_size_dw;
+	union {
+		struct {
+			uint8_t hour;
+			uint8_t min;
+			uint16_t sec;
+		};
+		uint32_t time;
+	};
+
+	char username[8];
+	char buildnumber[12];
+	uint32_t device_id;
+	uint32_t guc_sw_version;
+	uint32_t prod_preprod_fw;
+	uint32_t reserved[12];
+	uint32_t header_info;
+} __packed;
+
 struct guc_doorbell_info {
 	u32 db_status;
 	u32 cookie;
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index 3541f76..550921f 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -31,7 +31,7 @@
 #include "intel_guc.h"
 
 /**
- * DOC: GuC
+ * DOC: GuC-specific firmware loader
  *
  * intel_guc:
  * Top level structure of guc. It handles firmware loading and manages client
@@ -208,16 +208,6 @@
 /*
  * Transfer the firmware image to RAM for execution by the microcontroller.
  *
- * GuC Firmware layout:
- * +-------------------------------+  ----
- * |          CSS header           |  128B
- * | contains major/minor version  |
- * +-------------------------------+  ----
- * |             uCode             |
- * +-------------------------------+  ----
- * |         RSA signature         |  256B
- * +-------------------------------+  ----
- *
  * Architecturally, the DMA engine is bidirectional, and can potentially even
  * transfer between GTT locations. This functionality is left out of the API
  * for now as there is no need for it.
@@ -225,33 +215,29 @@
  * Note that GuC needs the CSS header plus uKernel code to be copied by the
  * DMA engine in one operation, whereas the RSA signature is loaded via MMIO.
  */
-
-#define UOS_CSS_HEADER_OFFSET		0
-#define UOS_VER_MINOR_OFFSET		0x44
-#define UOS_VER_MAJOR_OFFSET		0x46
-#define UOS_CSS_HEADER_SIZE		0x80
-#define UOS_RSA_SIG_SIZE		0x100
-
 static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
 {
 	struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
 	struct drm_i915_gem_object *fw_obj = guc_fw->guc_fw_obj;
 	unsigned long offset;
 	struct sg_table *sg = fw_obj->pages;
-	u32 status, ucode_size, rsa[UOS_RSA_SIG_SIZE / sizeof(u32)];
+	u32 status, rsa[UOS_RSA_SCRATCH_MAX_COUNT];
 	int i, ret = 0;
 
-	/* uCode size, also is where RSA signature starts */
-	offset = ucode_size = guc_fw->guc_fw_size - UOS_RSA_SIG_SIZE;
-	I915_WRITE(DMA_COPY_SIZE, ucode_size);
+	/* where RSA signature starts */
+	offset = guc_fw->rsa_offset;
 
 	/* Copy RSA signature from the fw image to HW for verification */
-	sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, UOS_RSA_SIG_SIZE, offset);
-	for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(u32); i++)
+	sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, sizeof(rsa), offset);
+	for (i = 0; i < UOS_RSA_SCRATCH_MAX_COUNT; i++)
 		I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]);
 
+	/* The header plus uCode will be copied to WOPCM via DMA, excluding any
+	 * other components */
+	I915_WRITE(DMA_COPY_SIZE, guc_fw->header_size + guc_fw->ucode_size);
+
 	/* Set the source address for the new blob */
-	offset = i915_gem_obj_ggtt_offset(fw_obj);
+	offset = i915_gem_obj_ggtt_offset(fw_obj) + guc_fw->header_offset;
 	I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
 	I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF);
 
@@ -322,8 +308,8 @@
 	I915_WRITE(GUC_SHIM_CONTROL, GUC_SHIM_CONTROL_VALUE);
 
 	/* WaDisableMinuteIaClockGating:skl,bxt */
-	if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) ||
-	    (IS_BROXTON(dev) && INTEL_REVID(dev) == BXT_REVID_A0)) {
+	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
+	    IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
 		I915_WRITE(GUC_SHIM_CONTROL, (I915_READ(GUC_SHIM_CONTROL) &
 					      ~GUC_ENABLE_MIA_CLOCK_GATING));
 	}
@@ -378,6 +364,9 @@
 	struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
 	int err = 0;
 
+	if (!i915.enable_guc_submission)
+		return 0;
+
 	DRM_DEBUG_DRIVER("GuC fw status: fetch %s, load %s\n",
 		intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status),
 		intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
@@ -457,10 +446,8 @@
 {
 	struct drm_i915_gem_object *obj;
 	const struct firmware *fw;
-	const u8 *css_header;
-	const size_t minsize = UOS_CSS_HEADER_SIZE + UOS_RSA_SIG_SIZE;
-	const size_t maxsize = GUC_WOPCM_SIZE_VALUE + UOS_RSA_SIG_SIZE
-			- 0x8000; /* 32k reserved (8K stack + 24k context) */
+	struct guc_css_header *css;
+	size_t size;
 	int err;
 
 	DRM_DEBUG_DRIVER("before requesting firmware: GuC fw fetch status %s\n",
@@ -474,12 +461,52 @@
 
 	DRM_DEBUG_DRIVER("fetch GuC fw from %s succeeded, fw %p\n",
 		guc_fw->guc_fw_path, fw);
-	DRM_DEBUG_DRIVER("firmware file size %zu (minimum %zu, maximum %zu)\n",
-		fw->size, minsize, maxsize);
 
-	/* Check the size of the blob befoe examining buffer contents */
-	if (fw->size < minsize || fw->size > maxsize)
+	/* Check the size of the blob before examining buffer contents */
+	if (fw->size < sizeof(struct guc_css_header)) {
+		DRM_ERROR("Firmware header is missing\n");
 		goto fail;
+	}
+
+	css = (struct guc_css_header *)fw->data;
+
+	/* Firmware bits always start from header */
+	guc_fw->header_offset = 0;
+	guc_fw->header_size = (css->header_size_dw - css->modulus_size_dw -
+		css->key_size_dw - css->exponent_size_dw) * sizeof(u32);
+
+	if (guc_fw->header_size != sizeof(struct guc_css_header)) {
+		DRM_ERROR("CSS header definition mismatch\n");
+		goto fail;
+	}
+
+	/* then, uCode */
+	guc_fw->ucode_offset = guc_fw->header_offset + guc_fw->header_size;
+	guc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
+
+	/* now RSA */
+	if (css->key_size_dw != UOS_RSA_SCRATCH_MAX_COUNT) {
+		DRM_ERROR("RSA key size is bad\n");
+		goto fail;
+	}
+	guc_fw->rsa_offset = guc_fw->ucode_offset + guc_fw->ucode_size;
+	guc_fw->rsa_size = css->key_size_dw * sizeof(u32);
+
+	/* At least, it should have header, uCode and RSA. Size of all three. */
+	size = guc_fw->header_size + guc_fw->ucode_size + guc_fw->rsa_size;
+	if (fw->size < size) {
+		DRM_ERROR("Missing firmware components\n");
+		goto fail;
+	}
+
+	/* Header and uCode will be loaded to WOPCM. Size of the two. */
+	size = guc_fw->header_size + guc_fw->ucode_size;
+
+	/* Top 32k of WOPCM is reserved (8K stack + 24k RC6 context). */
+	if (size > GUC_WOPCM_SIZE_VALUE - 0x8000) {
+		DRM_ERROR("Firmware is too large to fit in WOPCM\n");
+		goto fail;
+	}
 
 	/*
 	 * The GuC firmware image has the version number embedded at a well-known
@@ -487,9 +514,8 @@
 	 * TWO bytes each (i.e. u16), although all pointers and offsets are defined
 	 * in terms of bytes (u8).
 	 */
-	css_header = fw->data + UOS_CSS_HEADER_OFFSET;
-	guc_fw->guc_fw_major_found = *(u16 *)(css_header + UOS_VER_MAJOR_OFFSET);
-	guc_fw->guc_fw_minor_found = *(u16 *)(css_header + UOS_VER_MINOR_OFFSET);
+	guc_fw->guc_fw_major_found = css->guc_sw_version >> 16;
+	guc_fw->guc_fw_minor_found = css->guc_sw_version & 0xFFFF;
 
 	if (guc_fw->guc_fw_major_found != guc_fw->guc_fw_major_wanted ||
 	    guc_fw->guc_fw_minor_found < guc_fw->guc_fw_minor_wanted) {
@@ -566,6 +592,9 @@
 		fw_path = "";	/* unknown device */
 	}
 
+	if (!i915.enable_guc_submission)
+		return;
+
 	guc_fw->guc_dev = dev;
 	guc_fw->guc_fw_path = fw_path;
 	guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_NONE;
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index e6c035b..f16cd2a 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -113,10 +113,11 @@
 	}
 }
 
-static u32 hsw_dip_data_reg(struct drm_i915_private *dev_priv,
-			    enum transcoder cpu_transcoder,
-			    enum hdmi_infoframe_type type,
-			    int i)
+static i915_reg_t
+hsw_dip_data_reg(struct drm_i915_private *dev_priv,
+		 enum transcoder cpu_transcoder,
+		 enum hdmi_infoframe_type type,
+		 int i)
 {
 	switch (type) {
 	case HDMI_INFOFRAME_TYPE_AVI:
@@ -127,7 +128,7 @@
 		return HSW_TVIDEO_DIP_VS_DATA(cpu_transcoder, i);
 	default:
 		DRM_DEBUG_DRIVER("unknown info frame type %d\n", type);
-		return 0;
+		return INVALID_MMIO_REG;
 	}
 }
 
@@ -193,8 +194,9 @@
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
 	u32 val = I915_READ(reg);
+	int i;
 
 	WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
 
@@ -229,7 +231,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
-	int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
 	u32 val = I915_READ(reg);
 
 	if ((val & VIDEO_DIP_ENABLE) == 0)
@@ -251,8 +253,9 @@
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
 	u32 val = I915_READ(reg);
+	int i;
 
 	WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
 
@@ -289,8 +292,7 @@
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
-	u32 val = I915_READ(reg);
+	u32 val = I915_READ(TVIDEO_DIP_CTL(intel_crtc->pipe));
 
 	if ((val & VIDEO_DIP_ENABLE) == 0)
 		return false;
@@ -308,8 +310,9 @@
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	int i, reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
+	i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
 	u32 val = I915_READ(reg);
+	int i;
 
 	WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
 
@@ -344,8 +347,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
-	int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
-	u32 val = I915_READ(reg);
+	u32 val = I915_READ(VLV_TVIDEO_DIP_CTL(intel_crtc->pipe));
 
 	if ((val & VIDEO_DIP_ENABLE) == 0)
 		return false;
@@ -367,13 +369,13 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
 	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
-	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
-	u32 data_reg;
+	i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
+	i915_reg_t data_reg;
 	int i;
 	u32 val = I915_READ(ctl_reg);
 
 	data_reg = hsw_dip_data_reg(dev_priv, cpu_transcoder, type, 0);
-	if (data_reg == 0)
+	if (i915_mmio_reg_valid(data_reg))
 		return;
 
 	val &= ~hsw_infoframe_enable(type);
@@ -401,8 +403,7 @@
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
-	u32 val = I915_READ(ctl_reg);
+	u32 val = I915_READ(HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder));
 
 	return val & (VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW |
 		      VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW |
@@ -513,7 +514,7 @@
 	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 	struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
-	u32 reg = VIDEO_DIP_CTL;
+	i915_reg_t reg = VIDEO_DIP_CTL;
 	u32 val = I915_READ(reg);
 	u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
 
@@ -633,7 +634,8 @@
 {
 	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
 	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
-	u32 reg, val = 0;
+	i915_reg_t reg;
+	u32 val = 0;
 
 	if (HAS_DDI(dev_priv))
 		reg = HSW_TVIDEO_DIP_GCP(crtc->config->cpu_transcoder);
@@ -666,7 +668,7 @@
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 	struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
-	u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
 	u32 val = I915_READ(reg);
 	u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
 
@@ -717,7 +719,7 @@
 	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
-	u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
 	u32 val = I915_READ(reg);
 
 	assert_hdmi_port_disabled(intel_hdmi);
@@ -760,7 +762,7 @@
 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
-	u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
+	i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
 	u32 val = I915_READ(reg);
 	u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
 
@@ -811,7 +813,7 @@
 	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
-	u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
+	i915_reg_t reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
 	u32 val = I915_READ(reg);
 
 	assert_hdmi_port_disabled(intel_hdmi);
@@ -1108,6 +1110,13 @@
 	 * matching DP port to be enabled on transcoder A.
 	 */
 	if (HAS_PCH_IBX(dev) && crtc->pipe == PIPE_B) {
+		/*
+		 * We get CPU/PCH FIFO underruns on the other pipe when
+		 * doing the workaround. Sweep them under the rug.
+		 */
+		intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+		intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+
 		temp &= ~SDVO_PIPE_B_SELECT;
 		temp |= SDVO_ENABLE;
 		/*
@@ -1122,6 +1131,10 @@
 		temp &= ~SDVO_ENABLE;
 		I915_WRITE(intel_hdmi->hdmi_reg, temp);
 		POSTING_READ(intel_hdmi->hdmi_reg);
+
+		intel_wait_for_vblank_if_active(dev_priv->dev, PIPE_A);
+		intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
+		intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
 	}
 
 	intel_hdmi->set_infoframes(&encoder->base, false, NULL);
@@ -1338,14 +1351,15 @@
 	struct edid *edid = NULL;
 	bool connected = false;
 
-	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+	if (force) {
+		intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
 
-	if (force)
 		edid = drm_get_edid(connector,
 				    intel_gmbus_get_adapter(dev_priv,
 				    intel_hdmi->ddc_bus));
 
-	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
+		intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
+	}
 
 	to_intel_connector(connector)->detect_edid = edid;
 	if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
@@ -2040,7 +2054,7 @@
 		 * On BXT A0/A1, sw needs to activate DDIA HPD logic and
 		 * interrupts to check the external panel connection.
 		 */
-		if (IS_BROXTON(dev_priv) && (INTEL_REVID(dev) < BXT_REVID_B0))
+		if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1))
 			intel_encoder->hpd_pin = HPD_PORT_A;
 		else
 			intel_encoder->hpd_pin = HPD_PORT_B;
@@ -2132,8 +2146,10 @@
 	}
 }
 
-void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
+void intel_hdmi_init(struct drm_device *dev,
+		     i915_reg_t hdmi_reg, enum port port)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_digital_port *intel_dig_port;
 	struct intel_encoder *intel_encoder;
 	struct intel_connector *intel_connector;
@@ -2202,8 +2218,9 @@
 		intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI;
 
 	intel_dig_port->port = port;
+	dev_priv->dig_port_map[port] = intel_encoder;
 	intel_dig_port->hdmi.hdmi_reg = hdmi_reg;
-	intel_dig_port->dp.output_reg = 0;
+	intel_dig_port->dp.output_reg = INVALID_MMIO_REG;
 
 	intel_hdmi_init_connector(intel_dig_port, intel_connector);
 }
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 8324654..1110c83 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -36,7 +36,7 @@
 
 struct gmbus_pin {
 	const char *name;
-	int reg;
+	i915_reg_t reg;
 };
 
 /* Map gmbus pin pairs to names and registers. */
@@ -63,9 +63,9 @@
 };
 
 static const struct gmbus_pin gmbus_pins_bxt[] = {
-	[GMBUS_PIN_1_BXT] = { "dpb", PCH_GPIOB },
-	[GMBUS_PIN_2_BXT] = { "dpc", PCH_GPIOC },
-	[GMBUS_PIN_3_BXT] = { "misc", PCH_GPIOD },
+	[GMBUS_PIN_1_BXT] = { "dpb", GPIOB },
+	[GMBUS_PIN_2_BXT] = { "dpc", GPIOC },
+	[GMBUS_PIN_3_BXT] = { "misc", GPIOD },
 };
 
 /* pin is expected to be valid */
@@ -74,7 +74,7 @@
 {
 	if (IS_BROXTON(dev_priv))
 		return &gmbus_pins_bxt[pin];
-	else if (IS_SKYLAKE(dev_priv))
+	else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
 		return &gmbus_pins_skl[pin];
 	else if (IS_BROADWELL(dev_priv))
 		return &gmbus_pins_bdw[pin];
@@ -89,14 +89,15 @@
 
 	if (IS_BROXTON(dev_priv))
 		size = ARRAY_SIZE(gmbus_pins_bxt);
-	else if (IS_SKYLAKE(dev_priv))
+	else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
 		size = ARRAY_SIZE(gmbus_pins_skl);
 	else if (IS_BROADWELL(dev_priv))
 		size = ARRAY_SIZE(gmbus_pins_bdw);
 	else
 		size = ARRAY_SIZE(gmbus_pins);
 
-	return pin < size && get_gmbus_pin(dev_priv, pin)->reg;
+	return pin < size &&
+		i915_mmio_reg_valid(get_gmbus_pin(dev_priv, pin)->reg);
 }
 
 /* Intel GPIO access functions */
@@ -240,9 +241,8 @@
 
 	algo = &bus->bit_algo;
 
-	bus->gpio_reg = dev_priv->gpio_mmio_base +
-		get_gmbus_pin(dev_priv, pin)->reg;
-
+	bus->gpio_reg = _MMIO(dev_priv->gpio_mmio_base +
+			      i915_mmio_reg_offset(get_gmbus_pin(dev_priv, pin)->reg));
 	bus->adapter.algo_data = algo;
 	algo->setsda = set_data;
 	algo->setscl = set_clock;
@@ -628,12 +628,13 @@
 
 	if (HAS_PCH_NOP(dev))
 		return 0;
-	else if (HAS_PCH_SPLIT(dev))
-		dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA;
-	else if (IS_VALLEYVIEW(dev))
+
+	if (IS_VALLEYVIEW(dev))
 		dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE;
-	else
-		dev_priv->gpio_mmio_base = 0;
+	else if (!HAS_GMCH_DISPLAY(dev_priv))
+		dev_priv->gpio_mmio_base =
+			i915_mmio_reg_offset(PCH_GPIOA) -
+			i915_mmio_reg_offset(GPIOA);
 
 	mutex_init(&dev_priv->gmbus_mutex);
 	init_waitqueue_head(&dev_priv->gmbus_wait_queue);
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 88e12bd..4ebafab 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -190,16 +190,21 @@
 #define GEN8_CTX_L3LLC_COHERENT (1<<5)
 #define GEN8_CTX_PRIVILEGE (1<<8)
 
-#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) { \
+#define ASSIGN_CTX_REG(reg_state, pos, reg, val) do { \
+	(reg_state)[(pos)+0] = i915_mmio_reg_offset(reg); \
+	(reg_state)[(pos)+1] = (val); \
+} while (0)
+
+#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) do {		\
 	const u64 _addr = i915_page_dir_dma_addr((ppgtt), (n));	\
 	reg_state[CTX_PDP ## n ## _UDW+1] = upper_32_bits(_addr); \
 	reg_state[CTX_PDP ## n ## _LDW+1] = lower_32_bits(_addr); \
-}
+} while (0)
 
-#define ASSIGN_CTX_PML4(ppgtt, reg_state) { \
+#define ASSIGN_CTX_PML4(ppgtt, reg_state) do { \
 	reg_state[CTX_PDP0_UDW + 1] = upper_32_bits(px_dma(&ppgtt->pml4)); \
 	reg_state[CTX_PDP0_LDW + 1] = lower_32_bits(px_dma(&ppgtt->pml4)); \
-}
+} while (0)
 
 enum {
 	ADVANCED_CONTEXT = 0,
@@ -284,8 +289,8 @@
 {
 	struct drm_device *dev = ring->dev;
 
-	return ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) ||
-		(IS_BROXTON(dev) && INTEL_REVID(dev) == BXT_REVID_A0)) &&
+	return (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
+		IS_BXT_REVID(dev, 0, BXT_REVID_A1)) &&
 	       (ring->id == VCS || ring->id == VCS2);
 }
 
@@ -921,7 +926,7 @@
 
 		intel_logical_ring_emit(ringbuf, MI_NOOP);
 		intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(1));
-		intel_logical_ring_emit(ringbuf, INSTPM);
+		intel_logical_ring_emit_reg(ringbuf, INSTPM);
 		intel_logical_ring_emit(ringbuf, instp_mask << 16 | instp_mode);
 		intel_logical_ring_advance(ringbuf);
 
@@ -1096,7 +1101,7 @@
 
 	intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(w->count));
 	for (i = 0; i < w->count; i++) {
-		intel_logical_ring_emit(ringbuf, w->reg[i].addr);
+		intel_logical_ring_emit_reg(ringbuf, w->reg[i].addr);
 		intel_logical_ring_emit(ringbuf, w->reg[i].value);
 	}
 	intel_logical_ring_emit(ringbuf, MI_NOOP);
@@ -1120,6 +1125,8 @@
 		batch[__index] = (cmd);					\
 	} while (0)
 
+#define wa_ctx_emit_reg(batch, index, reg) \
+	wa_ctx_emit((batch), (index), i915_mmio_reg_offset(reg))
 
 /*
  * In this WA we need to set GEN8_L3SQCREG4[21:21] and reset it after
@@ -1149,17 +1156,17 @@
 	 * this batch updates GEN8_L3SQCREG4 with default value we need to
 	 * set this bit here to retain the WA during flush.
 	 */
-	if (IS_SKYLAKE(ring->dev) && INTEL_REVID(ring->dev) <= SKL_REVID_E0)
+	if (IS_SKL_REVID(ring->dev, 0, SKL_REVID_E0))
 		l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS;
 
 	wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8 |
 				   MI_SRM_LRM_GLOBAL_GTT));
-	wa_ctx_emit(batch, index, GEN8_L3SQCREG4);
+	wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4);
 	wa_ctx_emit(batch, index, ring->scratch.gtt_offset + 256);
 	wa_ctx_emit(batch, index, 0);
 
 	wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1));
-	wa_ctx_emit(batch, index, GEN8_L3SQCREG4);
+	wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4);
 	wa_ctx_emit(batch, index, l3sqc4_flush);
 
 	wa_ctx_emit(batch, index, GFX_OP_PIPE_CONTROL(6));
@@ -1172,7 +1179,7 @@
 
 	wa_ctx_emit(batch, index, (MI_LOAD_REGISTER_MEM_GEN8 |
 				   MI_SRM_LRM_GLOBAL_GTT));
-	wa_ctx_emit(batch, index, GEN8_L3SQCREG4);
+	wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4);
 	wa_ctx_emit(batch, index, ring->scratch.gtt_offset + 256);
 	wa_ctx_emit(batch, index, 0);
 
@@ -1314,8 +1321,8 @@
 	uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS);
 
 	/* WaDisableCtxRestoreArbitration:skl,bxt */
-	if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_D0)) ||
-	    (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0)))
+	if (IS_SKL_REVID(dev, 0, SKL_REVID_D0) ||
+	    IS_BXT_REVID(dev, 0, BXT_REVID_A1))
 		wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_DISABLE);
 
 	/* WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt */
@@ -1340,18 +1347,18 @@
 	uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS);
 
 	/* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */
-	if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_B0)) ||
-	    (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) {
+	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
+	    IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
 		wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1));
-		wa_ctx_emit(batch, index, GEN9_SLICE_COMMON_ECO_CHICKEN0);
+		wa_ctx_emit_reg(batch, index, GEN9_SLICE_COMMON_ECO_CHICKEN0);
 		wa_ctx_emit(batch, index,
 			    _MASKED_BIT_ENABLE(DISABLE_PIXEL_MASK_CAMMING));
 		wa_ctx_emit(batch, index, MI_NOOP);
 	}
 
 	/* WaDisableCtxRestoreArbitration:skl,bxt */
-	if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_D0)) ||
-	    (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0)))
+	if (IS_SKL_REVID(dev, 0, SKL_REVID_D0) ||
+	    IS_BXT_REVID(dev, 0, BXT_REVID_A1))
 		wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_ENABLE);
 
 	wa_ctx_emit(batch, index, MI_BATCH_BUFFER_END);
@@ -1472,12 +1479,6 @@
 	I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask));
 	I915_WRITE(RING_HWSTAM(ring->mmio_base), 0xffffffff);
 
-	if (ring->status_page.obj) {
-		I915_WRITE(RING_HWS_PGA(ring->mmio_base),
-			   (u32)ring->status_page.gfx_addr);
-		POSTING_READ(RING_HWS_PGA(ring->mmio_base));
-	}
-
 	I915_WRITE(RING_MODE_GEN7(ring),
 		   _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) |
 		   _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
@@ -1562,9 +1563,9 @@
 	for (i = GEN8_LEGACY_PDPES - 1; i >= 0; i--) {
 		const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i);
 
-		intel_logical_ring_emit(ringbuf, GEN8_RING_PDP_UDW(ring, i));
+		intel_logical_ring_emit_reg(ringbuf, GEN8_RING_PDP_UDW(ring, i));
 		intel_logical_ring_emit(ringbuf, upper_32_bits(pd_daddr));
-		intel_logical_ring_emit(ringbuf, GEN8_RING_PDP_LDW(ring, i));
+		intel_logical_ring_emit_reg(ringbuf, GEN8_RING_PDP_LDW(ring, i));
 		intel_logical_ring_emit(ringbuf, lower_32_bits(pd_daddr));
 	}
 
@@ -1923,6 +1924,7 @@
 	i915_gem_batch_pool_init(dev, &ring->batch_pool);
 	init_waitqueue_head(&ring->irq_queue);
 
+	INIT_LIST_HEAD(&ring->buffers);
 	INIT_LIST_HEAD(&ring->execlist_queue);
 	INIT_LIST_HEAD(&ring->execlist_retired_req_list);
 	spin_lock_init(&ring->execlist_lock);
@@ -1972,7 +1974,7 @@
 		ring->init_hw = gen8_init_render_ring;
 	ring->init_context = gen8_init_rcs_context;
 	ring->cleanup = intel_fini_pipe_control;
-	if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
+	if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
 		ring->get_seqno = bxt_a_get_seqno;
 		ring->set_seqno = bxt_a_set_seqno;
 	} else {
@@ -2024,7 +2026,7 @@
 		GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
 
 	ring->init_hw = gen8_init_common_ring;
-	if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
+	if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
 		ring->get_seqno = bxt_a_get_seqno;
 		ring->set_seqno = bxt_a_set_seqno;
 	} else {
@@ -2079,7 +2081,7 @@
 		GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
 
 	ring->init_hw = gen8_init_common_ring;
-	if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
+	if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
 		ring->get_seqno = bxt_a_get_seqno;
 		ring->set_seqno = bxt_a_set_seqno;
 	} else {
@@ -2109,7 +2111,7 @@
 		GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
 
 	ring->init_hw = gen8_init_common_ring;
-	if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
+	if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
 		ring->get_seqno = bxt_a_get_seqno;
 		ring->set_seqno = bxt_a_set_seqno;
 	} else {
@@ -2263,46 +2265,31 @@
 	 * only for the first context restore: on a subsequent save, the GPU will
 	 * recreate this batchbuffer with new values (including all the missing
 	 * MI_LOAD_REGISTER_IMM commands that we are not initializing here). */
-	if (ring->id == RCS)
-		reg_state[CTX_LRI_HEADER_0] = MI_LOAD_REGISTER_IMM(14);
-	else
-		reg_state[CTX_LRI_HEADER_0] = MI_LOAD_REGISTER_IMM(11);
-	reg_state[CTX_LRI_HEADER_0] |= MI_LRI_FORCE_POSTED;
-	reg_state[CTX_CONTEXT_CONTROL] = RING_CONTEXT_CONTROL(ring);
-	reg_state[CTX_CONTEXT_CONTROL+1] =
-		_MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH |
-				   CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT |
-				   CTX_CTRL_RS_CTX_ENABLE);
-	reg_state[CTX_RING_HEAD] = RING_HEAD(ring->mmio_base);
-	reg_state[CTX_RING_HEAD+1] = 0;
-	reg_state[CTX_RING_TAIL] = RING_TAIL(ring->mmio_base);
-	reg_state[CTX_RING_TAIL+1] = 0;
-	reg_state[CTX_RING_BUFFER_START] = RING_START(ring->mmio_base);
+	reg_state[CTX_LRI_HEADER_0] =
+		MI_LOAD_REGISTER_IMM(ring->id == RCS ? 14 : 11) | MI_LRI_FORCE_POSTED;
+	ASSIGN_CTX_REG(reg_state, CTX_CONTEXT_CONTROL, RING_CONTEXT_CONTROL(ring),
+		       _MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH |
+					  CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT |
+					  CTX_CTRL_RS_CTX_ENABLE));
+	ASSIGN_CTX_REG(reg_state, CTX_RING_HEAD, RING_HEAD(ring->mmio_base), 0);
+	ASSIGN_CTX_REG(reg_state, CTX_RING_TAIL, RING_TAIL(ring->mmio_base), 0);
 	/* Ring buffer start address is not known until the buffer is pinned.
 	 * It is written to the context image in execlists_update_context()
 	 */
-	reg_state[CTX_RING_BUFFER_CONTROL] = RING_CTL(ring->mmio_base);
-	reg_state[CTX_RING_BUFFER_CONTROL+1] =
-			((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID;
-	reg_state[CTX_BB_HEAD_U] = ring->mmio_base + 0x168;
-	reg_state[CTX_BB_HEAD_U+1] = 0;
-	reg_state[CTX_BB_HEAD_L] = ring->mmio_base + 0x140;
-	reg_state[CTX_BB_HEAD_L+1] = 0;
-	reg_state[CTX_BB_STATE] = ring->mmio_base + 0x110;
-	reg_state[CTX_BB_STATE+1] = (1<<5);
-	reg_state[CTX_SECOND_BB_HEAD_U] = ring->mmio_base + 0x11c;
-	reg_state[CTX_SECOND_BB_HEAD_U+1] = 0;
-	reg_state[CTX_SECOND_BB_HEAD_L] = ring->mmio_base + 0x114;
-	reg_state[CTX_SECOND_BB_HEAD_L+1] = 0;
-	reg_state[CTX_SECOND_BB_STATE] = ring->mmio_base + 0x118;
-	reg_state[CTX_SECOND_BB_STATE+1] = 0;
+	ASSIGN_CTX_REG(reg_state, CTX_RING_BUFFER_START, RING_START(ring->mmio_base), 0);
+	ASSIGN_CTX_REG(reg_state, CTX_RING_BUFFER_CONTROL, RING_CTL(ring->mmio_base),
+		       ((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID);
+	ASSIGN_CTX_REG(reg_state, CTX_BB_HEAD_U, RING_BBADDR_UDW(ring->mmio_base), 0);
+	ASSIGN_CTX_REG(reg_state, CTX_BB_HEAD_L, RING_BBADDR(ring->mmio_base), 0);
+	ASSIGN_CTX_REG(reg_state, CTX_BB_STATE, RING_BBSTATE(ring->mmio_base),
+		       RING_BB_PPGTT);
+	ASSIGN_CTX_REG(reg_state, CTX_SECOND_BB_HEAD_U, RING_SBBADDR_UDW(ring->mmio_base), 0);
+	ASSIGN_CTX_REG(reg_state, CTX_SECOND_BB_HEAD_L, RING_SBBADDR(ring->mmio_base), 0);
+	ASSIGN_CTX_REG(reg_state, CTX_SECOND_BB_STATE, RING_SBBSTATE(ring->mmio_base), 0);
 	if (ring->id == RCS) {
-		reg_state[CTX_BB_PER_CTX_PTR] = ring->mmio_base + 0x1c0;
-		reg_state[CTX_BB_PER_CTX_PTR+1] = 0;
-		reg_state[CTX_RCS_INDIRECT_CTX] = ring->mmio_base + 0x1c4;
-		reg_state[CTX_RCS_INDIRECT_CTX+1] = 0;
-		reg_state[CTX_RCS_INDIRECT_CTX_OFFSET] = ring->mmio_base + 0x1c8;
-		reg_state[CTX_RCS_INDIRECT_CTX_OFFSET+1] = 0;
+		ASSIGN_CTX_REG(reg_state, CTX_BB_PER_CTX_PTR, RING_BB_PER_CTX_PTR(ring->mmio_base), 0);
+		ASSIGN_CTX_REG(reg_state, CTX_RCS_INDIRECT_CTX, RING_INDIRECT_CTX(ring->mmio_base), 0);
+		ASSIGN_CTX_REG(reg_state, CTX_RCS_INDIRECT_CTX_OFFSET, RING_INDIRECT_CTX_OFFSET(ring->mmio_base), 0);
 		if (ring->wa_ctx.obj) {
 			struct i915_ctx_workarounds *wa_ctx = &ring->wa_ctx;
 			uint32_t ggtt_offset = i915_gem_obj_ggtt_offset(wa_ctx->obj);
@@ -2319,18 +2306,17 @@
 				0x01;
 		}
 	}
-	reg_state[CTX_LRI_HEADER_1] = MI_LOAD_REGISTER_IMM(9);
-	reg_state[CTX_LRI_HEADER_1] |= MI_LRI_FORCE_POSTED;
-	reg_state[CTX_CTX_TIMESTAMP] = ring->mmio_base + 0x3a8;
-	reg_state[CTX_CTX_TIMESTAMP+1] = 0;
-	reg_state[CTX_PDP3_UDW] = GEN8_RING_PDP_UDW(ring, 3);
-	reg_state[CTX_PDP3_LDW] = GEN8_RING_PDP_LDW(ring, 3);
-	reg_state[CTX_PDP2_UDW] = GEN8_RING_PDP_UDW(ring, 2);
-	reg_state[CTX_PDP2_LDW] = GEN8_RING_PDP_LDW(ring, 2);
-	reg_state[CTX_PDP1_UDW] = GEN8_RING_PDP_UDW(ring, 1);
-	reg_state[CTX_PDP1_LDW] = GEN8_RING_PDP_LDW(ring, 1);
-	reg_state[CTX_PDP0_UDW] = GEN8_RING_PDP_UDW(ring, 0);
-	reg_state[CTX_PDP0_LDW] = GEN8_RING_PDP_LDW(ring, 0);
+	reg_state[CTX_LRI_HEADER_1] = MI_LOAD_REGISTER_IMM(9) | MI_LRI_FORCE_POSTED;
+	ASSIGN_CTX_REG(reg_state, CTX_CTX_TIMESTAMP, RING_CTX_TIMESTAMP(ring->mmio_base), 0);
+	/* PDP values well be assigned later if needed */
+	ASSIGN_CTX_REG(reg_state, CTX_PDP3_UDW, GEN8_RING_PDP_UDW(ring, 3), 0);
+	ASSIGN_CTX_REG(reg_state, CTX_PDP3_LDW, GEN8_RING_PDP_LDW(ring, 3), 0);
+	ASSIGN_CTX_REG(reg_state, CTX_PDP2_UDW, GEN8_RING_PDP_UDW(ring, 2), 0);
+	ASSIGN_CTX_REG(reg_state, CTX_PDP2_LDW, GEN8_RING_PDP_LDW(ring, 2), 0);
+	ASSIGN_CTX_REG(reg_state, CTX_PDP1_UDW, GEN8_RING_PDP_UDW(ring, 1), 0);
+	ASSIGN_CTX_REG(reg_state, CTX_PDP1_LDW, GEN8_RING_PDP_LDW(ring, 1), 0);
+	ASSIGN_CTX_REG(reg_state, CTX_PDP0_UDW, GEN8_RING_PDP_UDW(ring, 0), 0);
+	ASSIGN_CTX_REG(reg_state, CTX_PDP0_LDW, GEN8_RING_PDP_LDW(ring, 0), 0);
 
 	if (USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) {
 		/* 64b PPGTT (48bit canonical)
@@ -2352,8 +2338,8 @@
 
 	if (ring->id == RCS) {
 		reg_state[CTX_LRI_HEADER_2] = MI_LOAD_REGISTER_IMM(1);
-		reg_state[CTX_R_PWR_CLK_STATE] = GEN8_R_PWR_CLK_STATE;
-		reg_state[CTX_R_PWR_CLK_STATE+1] = make_rpcs(dev);
+		ASSIGN_CTX_REG(reg_state, CTX_R_PWR_CLK_STATE, GEN8_R_PWR_CLK_STATE,
+			       make_rpcs(dev));
 	}
 
 	kunmap_atomic(reg_state);
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
index 4e60d54..0b821b9 100644
--- a/drivers/gpu/drm/i915/intel_lrc.h
+++ b/drivers/gpu/drm/i915/intel_lrc.h
@@ -29,16 +29,16 @@
 #define GEN8_CSB_PTR_MASK 0x07
 
 /* Execlists regs */
-#define RING_ELSP(ring)			((ring)->mmio_base+0x230)
-#define RING_EXECLIST_STATUS_LO(ring)	((ring)->mmio_base+0x234)
-#define RING_EXECLIST_STATUS_HI(ring)	((ring)->mmio_base+0x234 + 4)
-#define RING_CONTEXT_CONTROL(ring)	((ring)->mmio_base+0x244)
+#define RING_ELSP(ring)				_MMIO((ring)->mmio_base + 0x230)
+#define RING_EXECLIST_STATUS_LO(ring)		_MMIO((ring)->mmio_base + 0x234)
+#define RING_EXECLIST_STATUS_HI(ring)		_MMIO((ring)->mmio_base + 0x234 + 4)
+#define RING_CONTEXT_CONTROL(ring)		_MMIO((ring)->mmio_base + 0x244)
 #define	  CTX_CTRL_INHIBIT_SYN_CTX_SWITCH	(1 << 3)
 #define	  CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT	(1 << 0)
 #define   CTX_CTRL_RS_CTX_ENABLE                (1 << 1)
-#define RING_CONTEXT_STATUS_BUF_LO(ring, i)	((ring)->mmio_base+0x370 + (i) * 8)
-#define RING_CONTEXT_STATUS_BUF_HI(ring, i)	((ring)->mmio_base+0x370 + (i) * 8 + 4)
-#define RING_CONTEXT_STATUS_PTR(ring)	((ring)->mmio_base+0x3a0)
+#define RING_CONTEXT_STATUS_BUF_LO(ring, i)	_MMIO((ring)->mmio_base + 0x370 + (i) * 8)
+#define RING_CONTEXT_STATUS_BUF_HI(ring, i)	_MMIO((ring)->mmio_base + 0x370 + (i) * 8 + 4)
+#define RING_CONTEXT_STATUS_PTR(ring)		_MMIO((ring)->mmio_base + 0x3a0)
 
 /* Logical Rings */
 int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request);
@@ -70,6 +70,11 @@
 	iowrite32(data, ringbuf->virtual_start + ringbuf->tail);
 	ringbuf->tail += 4;
 }
+static inline void intel_logical_ring_emit_reg(struct intel_ringbuffer *ringbuf,
+					       i915_reg_t reg)
+{
+	intel_logical_ring_emit(ringbuf, i915_mmio_reg_offset(reg));
+}
 
 /* Logical Ring Contexts */
 
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 7f39b8a..61f1145 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -51,7 +51,7 @@
 	struct intel_encoder base;
 
 	bool is_dual_link;
-	u32 reg;
+	i915_reg_t reg;
 	u32 a3_power;
 
 	struct intel_lvds_connector *attached_connector;
@@ -210,7 +210,7 @@
 	struct intel_connector *intel_connector =
 		&lvds_encoder->attached_connector->base;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 ctl_reg, stat_reg;
+	i915_reg_t ctl_reg, stat_reg;
 
 	if (HAS_PCH_SPLIT(dev)) {
 		ctl_reg = PCH_PP_CONTROL;
@@ -235,7 +235,7 @@
 	struct drm_device *dev = encoder->base.dev;
 	struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 ctl_reg, stat_reg;
+	i915_reg_t ctl_reg, stat_reg;
 
 	if (HAS_PCH_SPLIT(dev)) {
 		ctl_reg = PCH_PP_CONTROL;
@@ -939,7 +939,7 @@
 	struct drm_display_mode *downclock_mode = NULL;
 	struct edid *edid;
 	struct drm_crtc *crtc;
-	u32 lvds_reg;
+	i915_reg_t lvds_reg;
 	u32 lvds;
 	int pipe;
 	u8 pin;
@@ -1164,8 +1164,7 @@
 	DRM_DEBUG_KMS("detected %s-link lvds configuration\n",
 		      lvds_encoder->is_dual_link ? "dual" : "single");
 
-	lvds_encoder->a3_power = I915_READ(lvds_encoder->reg) &
-				 LVDS_A3_POWER_MASK;
+	lvds_encoder->a3_power = lvds & LVDS_A3_POWER_MASK;
 
 	lvds_connector->lid_notifier.notifier_call = intel_lid_notify;
 	if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) {
diff --git a/drivers/gpu/drm/i915/intel_mocs.c b/drivers/gpu/drm/i915/intel_mocs.c
index 6d3c6c0..fed7bea 100644
--- a/drivers/gpu/drm/i915/intel_mocs.c
+++ b/drivers/gpu/drm/i915/intel_mocs.c
@@ -143,7 +143,7 @@
 {
 	bool result = false;
 
-	if (IS_SKYLAKE(dev)) {
+	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
 		table->size  = ARRAY_SIZE(skylake_mocs_table);
 		table->table = skylake_mocs_table;
 		result = true;
@@ -159,11 +159,30 @@
 	return result;
 }
 
+static i915_reg_t mocs_register(enum intel_ring_id ring, int index)
+{
+	switch (ring) {
+	case RCS:
+		return GEN9_GFX_MOCS(index);
+	case VCS:
+		return GEN9_MFX0_MOCS(index);
+	case BCS:
+		return GEN9_BLT_MOCS(index);
+	case VECS:
+		return GEN9_VEBOX_MOCS(index);
+	case VCS2:
+		return GEN9_MFX1_MOCS(index);
+	default:
+		MISSING_CASE(ring);
+		return INVALID_MMIO_REG;
+	}
+}
+
 /**
  * emit_mocs_control_table() - emit the mocs control table
  * @req:	Request to set up the MOCS table for.
  * @table:	The values to program into the control regs.
- * @reg_base:	The base for the engine that needs to be programmed.
+ * @ring:	The engine for whom to emit the registers.
  *
  * This function simply emits a MI_LOAD_REGISTER_IMM command for the
  * given table starting at the given address.
@@ -172,7 +191,7 @@
  */
 static int emit_mocs_control_table(struct drm_i915_gem_request *req,
 				   const struct drm_i915_mocs_table *table,
-				   u32 reg_base)
+				   enum intel_ring_id ring)
 {
 	struct intel_ringbuffer *ringbuf = req->ringbuf;
 	unsigned int index;
@@ -191,7 +210,7 @@
 				MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
 
 	for (index = 0; index < table->size; index++) {
-		intel_logical_ring_emit(ringbuf, reg_base + index * 4);
+		intel_logical_ring_emit_reg(ringbuf, mocs_register(ring, index));
 		intel_logical_ring_emit(ringbuf,
 					table->table[index].control_value);
 	}
@@ -205,7 +224,7 @@
 	 * that value to all the used entries.
 	 */
 	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
-		intel_logical_ring_emit(ringbuf, reg_base + index * 4);
+		intel_logical_ring_emit_reg(ringbuf, mocs_register(ring, index));
 		intel_logical_ring_emit(ringbuf, table->table[0].control_value);
 	}
 
@@ -253,7 +272,7 @@
 		value = (table->table[count].l3cc_value & 0xffff) |
 			((table->table[count + 1].l3cc_value & 0xffff) << 16);
 
-		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + i * 4);
+		intel_logical_ring_emit_reg(ringbuf, GEN9_LNCFCMOCS(i));
 		intel_logical_ring_emit(ringbuf, value);
 	}
 
@@ -270,7 +289,7 @@
 	 * they are reserved by the hardware.
 	 */
 	for (; i < GEN9_NUM_MOCS_ENTRIES / 2; i++) {
-		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + i * 4);
+		intel_logical_ring_emit_reg(ringbuf, GEN9_LNCFCMOCS(i));
 		intel_logical_ring_emit(ringbuf, value);
 
 		value = filler;
@@ -304,26 +323,16 @@
 	int ret;
 
 	if (get_mocs_settings(req->ring->dev, &t)) {
+		struct drm_i915_private *dev_priv = req->i915;
+		struct intel_engine_cs *ring;
+		enum intel_ring_id ring_id;
+
 		/* Program the control registers */
-		ret = emit_mocs_control_table(req, &t, GEN9_GFX_MOCS_0);
-		if (ret)
-			return ret;
-
-		ret = emit_mocs_control_table(req, &t, GEN9_MFX0_MOCS_0);
-		if (ret)
-			return ret;
-
-		ret = emit_mocs_control_table(req, &t, GEN9_MFX1_MOCS_0);
-		if (ret)
-			return ret;
-
-		ret = emit_mocs_control_table(req, &t, GEN9_VEBOX_MOCS_0);
-		if (ret)
-			return ret;
-
-		ret = emit_mocs_control_table(req, &t, GEN9_BLT_MOCS_0);
-		if (ret)
-			return ret;
+		for_each_ring(ring, dev_priv, ring_id) {
+			ret = emit_mocs_control_table(req, &t, ring_id);
+			if (ret)
+				return ret;
+		}
 
 		/* Now program the l3cc registers */
 		ret = emit_mocs_l3cc_table(req, &t);
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
index 6dc13c0..e362a30 100644
--- a/drivers/gpu/drm/i915/intel_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -682,7 +682,7 @@
 	}
 
 	if (!acpi_video_bus) {
-		DRM_ERROR("No ACPI video bus found\n");
+		DRM_DEBUG_KMS("No ACPI video bus found\n");
 		return;
 	}
 
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 4445426..76f1980 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -749,7 +749,7 @@
 	if (ret != 0)
 		return ret;
 
-	ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL, NULL,
+	ret = i915_gem_object_pin_to_display_plane(new_bo, 0,
 						   &i915_ggtt_view_normal);
 	if (ret != 0)
 		return ret;
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index f091ad1..038a81d 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -1708,13 +1708,6 @@
 	return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2;
 }
 
-struct skl_pipe_wm_parameters {
-	bool active;
-	uint32_t pipe_htotal;
-	uint32_t pixel_rate; /* in KHz */
-	struct intel_plane_wm_parameters plane[I915_MAX_PLANES];
-};
-
 struct ilk_wm_maximums {
 	uint16_t pri;
 	uint16_t spr;
@@ -1722,13 +1715,6 @@
 	uint16_t fbc;
 };
 
-/* used in computing the new watermarks state */
-struct intel_wm_config {
-	unsigned int num_pipes_active;
-	bool sprites_enabled;
-	bool sprites_scaled;
-};
-
 /*
  * For both WM_PIPE and WM_LP.
  * mem_value must be in 0.1us units.
@@ -1979,9 +1965,11 @@
 				 const struct intel_crtc *intel_crtc,
 				 int level,
 				 struct intel_crtc_state *cstate,
+				 struct intel_plane_state *pristate,
+				 struct intel_plane_state *sprstate,
+				 struct intel_plane_state *curstate,
 				 struct intel_wm_level *result)
 {
-	struct intel_plane *intel_plane;
 	uint16_t pri_latency = dev_priv->wm.pri_latency[level];
 	uint16_t spr_latency = dev_priv->wm.spr_latency[level];
 	uint16_t cur_latency = dev_priv->wm.cur_latency[level];
@@ -1993,29 +1981,11 @@
 		cur_latency *= 5;
 	}
 
-	for_each_intel_plane_on_crtc(dev_priv->dev, intel_crtc, intel_plane) {
-		struct intel_plane_state *pstate =
-			to_intel_plane_state(intel_plane->base.state);
-
-		switch (intel_plane->base.type) {
-		case DRM_PLANE_TYPE_PRIMARY:
-			result->pri_val = ilk_compute_pri_wm(cstate, pstate,
-							     pri_latency,
-							     level);
-			result->fbc_val = ilk_compute_fbc_wm(cstate, pstate,
-							     result->pri_val);
-			break;
-		case DRM_PLANE_TYPE_OVERLAY:
-			result->spr_val = ilk_compute_spr_wm(cstate, pstate,
-							     spr_latency);
-			break;
-		case DRM_PLANE_TYPE_CURSOR:
-			result->cur_val = ilk_compute_cur_wm(cstate, pstate,
-							     cur_latency);
-			break;
-		}
-	}
-
+	result->pri_val = ilk_compute_pri_wm(cstate, pristate,
+					     pri_latency, level);
+	result->spr_val = ilk_compute_spr_wm(cstate, sprstate, spr_latency);
+	result->cur_val = ilk_compute_cur_wm(cstate, curstate, cur_latency);
+	result->fbc_val = ilk_compute_fbc_wm(cstate, pristate, result->pri_val);
 	result->enable = true;
 }
 
@@ -2274,34 +2244,19 @@
 	intel_print_wm_latency(dev, "Gen9 Plane", dev_priv->wm.skl_latency);
 }
 
-static void ilk_compute_wm_config(struct drm_device *dev,
-				  struct intel_wm_config *config)
-{
-	struct intel_crtc *intel_crtc;
-
-	/* Compute the currently _active_ config */
-	for_each_intel_crtc(dev, intel_crtc) {
-		const struct intel_pipe_wm *wm = &intel_crtc->wm.active;
-
-		if (!wm->pipe_enabled)
-			continue;
-
-		config->sprites_enabled |= wm->sprites_enabled;
-		config->sprites_scaled |= wm->sprites_scaled;
-		config->num_pipes_active++;
-	}
-}
-
 /* Compute new watermarks for the pipe */
-static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate,
-				  struct intel_pipe_wm *pipe_wm)
+static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc,
+			       struct drm_atomic_state *state)
 {
-	struct drm_crtc *crtc = cstate->base.crtc;
-	struct drm_device *dev = crtc->dev;
+	struct intel_pipe_wm *pipe_wm;
+	struct drm_device *dev = intel_crtc->base.dev;
 	const struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct intel_crtc_state *cstate = NULL;
 	struct intel_plane *intel_plane;
+	struct drm_plane_state *ps;
+	struct intel_plane_state *pristate = NULL;
 	struct intel_plane_state *sprstate = NULL;
+	struct intel_plane_state *curstate = NULL;
 	int level, max_level = ilk_wm_max_level(dev);
 	/* LP0 watermark maximums depend on this pipe alone */
 	struct intel_wm_config config = {
@@ -2309,11 +2264,24 @@
 	};
 	struct ilk_wm_maximums max;
 
+	cstate = intel_atomic_get_crtc_state(state, intel_crtc);
+	if (IS_ERR(cstate))
+		return PTR_ERR(cstate);
+
+	pipe_wm = &cstate->wm.optimal.ilk;
+
 	for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
-		if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY) {
-			sprstate = to_intel_plane_state(intel_plane->base.state);
-			break;
-		}
+		ps = drm_atomic_get_plane_state(state,
+						&intel_plane->base);
+		if (IS_ERR(ps))
+			return PTR_ERR(ps);
+
+		if (intel_plane->base.type == DRM_PLANE_TYPE_PRIMARY)
+			pristate = to_intel_plane_state(ps);
+		else if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY)
+			sprstate = to_intel_plane_state(ps);
+		else if (intel_plane->base.type == DRM_PLANE_TYPE_CURSOR)
+			curstate = to_intel_plane_state(ps);
 	}
 
 	config.sprites_enabled = sprstate->visible;
@@ -2322,7 +2290,7 @@
 		drm_rect_height(&sprstate->dst) != drm_rect_height(&sprstate->src) >> 16);
 
 	pipe_wm->pipe_enabled = cstate->base.active;
-	pipe_wm->sprites_enabled = sprstate->visible;
+	pipe_wm->sprites_enabled = config.sprites_enabled;
 	pipe_wm->sprites_scaled = config.sprites_scaled;
 
 	/* ILK/SNB: LP2+ watermarks only w/o sprites */
@@ -2333,24 +2301,27 @@
 	if (config.sprites_scaled)
 		max_level = 0;
 
-	ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate, &pipe_wm->wm[0]);
+	ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate,
+			     pristate, sprstate, curstate, &pipe_wm->wm[0]);
 
 	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
-		pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc);
+		pipe_wm->linetime = hsw_compute_linetime_wm(dev,
+							    &intel_crtc->base);
 
 	/* LP0 watermarks always use 1/2 DDB partitioning */
 	ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max);
 
 	/* At least LP0 must be valid */
 	if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0]))
-		return false;
+		return -EINVAL;
 
 	ilk_compute_wm_reg_maximums(dev, 1, &max);
 
 	for (level = 1; level <= max_level; level++) {
 		struct intel_wm_level wm = {};
 
-		ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate, &wm);
+		ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate,
+				     pristate, sprstate, curstate, &wm);
 
 		/*
 		 * Disable any watermark level that exceeds the
@@ -2363,7 +2334,7 @@
 		pipe_wm->wm[level] = wm;
 	}
 
-	return true;
+	return 0;
 }
 
 /*
@@ -2378,7 +2349,9 @@
 	ret_wm->enable = true;
 
 	for_each_intel_crtc(dev, intel_crtc) {
-		const struct intel_pipe_wm *active = &intel_crtc->wm.active;
+		const struct intel_crtc_state *cstate =
+			to_intel_crtc_state(intel_crtc->base.state);
+		const struct intel_pipe_wm *active = &cstate->wm.optimal.ilk;
 		const struct intel_wm_level *wm = &active->wm[level];
 
 		if (!active->pipe_enabled)
@@ -2526,14 +2499,15 @@
 
 	/* LP0 register values */
 	for_each_intel_crtc(dev, intel_crtc) {
+		const struct intel_crtc_state *cstate =
+			to_intel_crtc_state(intel_crtc->base.state);
 		enum pipe pipe = intel_crtc->pipe;
-		const struct intel_wm_level *r =
-			&intel_crtc->wm.active.wm[0];
+		const struct intel_wm_level *r = &cstate->wm.optimal.ilk.wm[0];
 
 		if (WARN_ON(!r->enable))
 			continue;
 
-		results->wm_linetime[pipe] = intel_crtc->wm.active.linetime;
+		results->wm_linetime[pipe] = cstate->wm.optimal.ilk.linetime;
 
 		results->wm_pipe[pipe] =
 			(r->pri_val << WM0_PIPE_PLANE_SHIFT) |
@@ -2755,18 +2729,40 @@
 #define SKL_DDB_SIZE		896	/* in blocks */
 #define BXT_DDB_SIZE		512
 
+/*
+ * Return the index of a plane in the SKL DDB and wm result arrays.  Primary
+ * plane is always in slot 0, cursor is always in slot I915_MAX_PLANES-1, and
+ * other universal planes are in indices 1..n.  Note that this may leave unused
+ * indices between the top "sprite" plane and the cursor.
+ */
+static int
+skl_wm_plane_id(const struct intel_plane *plane)
+{
+	switch (plane->base.type) {
+	case DRM_PLANE_TYPE_PRIMARY:
+		return 0;
+	case DRM_PLANE_TYPE_CURSOR:
+		return PLANE_CURSOR;
+	case DRM_PLANE_TYPE_OVERLAY:
+		return plane->plane + 1;
+	default:
+		MISSING_CASE(plane->base.type);
+		return plane->plane;
+	}
+}
+
 static void
 skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
-				   struct drm_crtc *for_crtc,
+				   const struct intel_crtc_state *cstate,
 				   const struct intel_wm_config *config,
-				   const struct skl_pipe_wm_parameters *params,
 				   struct skl_ddb_entry *alloc /* out */)
 {
+	struct drm_crtc *for_crtc = cstate->base.crtc;
 	struct drm_crtc *crtc;
 	unsigned int pipe_size, ddb_size;
 	int nth_active_pipe;
 
-	if (!params->active) {
+	if (!cstate->base.active) {
 		alloc->start = 0;
 		alloc->end = 0;
 		return;
@@ -2837,19 +2833,29 @@
 }
 
 static unsigned int
-skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p, int y)
+skl_plane_relative_data_rate(const struct intel_crtc_state *cstate,
+			     const struct drm_plane_state *pstate,
+			     int y)
 {
+	struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
+	struct drm_framebuffer *fb = pstate->fb;
 
 	/* for planar format */
-	if (p->y_bytes_per_pixel) {
+	if (fb->pixel_format == DRM_FORMAT_NV12) {
 		if (y)  /* y-plane data rate */
-			return p->horiz_pixels * p->vert_pixels * p->y_bytes_per_pixel;
+			return intel_crtc->config->pipe_src_w *
+				intel_crtc->config->pipe_src_h *
+				drm_format_plane_cpp(fb->pixel_format, 0);
 		else    /* uv-plane data rate */
-			return (p->horiz_pixels/2) * (p->vert_pixels/2) * p->bytes_per_pixel;
+			return (intel_crtc->config->pipe_src_w/2) *
+				(intel_crtc->config->pipe_src_h/2) *
+				drm_format_plane_cpp(fb->pixel_format, 1);
 	}
 
 	/* for packed formats */
-	return p->horiz_pixels * p->vert_pixels * p->bytes_per_pixel;
+	return intel_crtc->config->pipe_src_w *
+		intel_crtc->config->pipe_src_h *
+		drm_format_plane_cpp(fb->pixel_format, 0);
 }
 
 /*
@@ -2858,46 +2864,55 @@
  *   3 * 4096 * 8192  * 4 < 2^32
  */
 static unsigned int
-skl_get_total_relative_data_rate(struct intel_crtc *intel_crtc,
-				 const struct skl_pipe_wm_parameters *params)
+skl_get_total_relative_data_rate(const struct intel_crtc_state *cstate)
 {
+	struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
+	struct drm_device *dev = intel_crtc->base.dev;
+	const struct intel_plane *intel_plane;
 	unsigned int total_data_rate = 0;
-	int plane;
 
-	for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
-		const struct intel_plane_wm_parameters *p;
+	for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+		const struct drm_plane_state *pstate = intel_plane->base.state;
 
-		p = &params->plane[plane];
-		if (!p->enabled)
+		if (pstate->fb == NULL)
 			continue;
 
-		total_data_rate += skl_plane_relative_data_rate(p, 0); /* packed/uv */
-		if (p->y_bytes_per_pixel) {
-			total_data_rate += skl_plane_relative_data_rate(p, 1); /* y-plane */
-		}
+		if (intel_plane->base.type == DRM_PLANE_TYPE_CURSOR)
+			continue;
+
+		/* packed/uv */
+		total_data_rate += skl_plane_relative_data_rate(cstate,
+								pstate,
+								0);
+
+		if (pstate->fb->pixel_format == DRM_FORMAT_NV12)
+			/* y-plane */
+			total_data_rate += skl_plane_relative_data_rate(cstate,
+									pstate,
+									1);
 	}
 
 	return total_data_rate;
 }
 
 static void
-skl_allocate_pipe_ddb(struct drm_crtc *crtc,
-		      const struct intel_wm_config *config,
-		      const struct skl_pipe_wm_parameters *params,
+skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
 		      struct skl_ddb_allocation *ddb /* out */)
 {
+	struct drm_crtc *crtc = cstate->base.crtc;
 	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct intel_wm_config *config = &dev_priv->wm.config;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct intel_plane *intel_plane;
 	enum pipe pipe = intel_crtc->pipe;
 	struct skl_ddb_entry *alloc = &ddb->pipe[pipe];
 	uint16_t alloc_size, start, cursor_blocks;
 	uint16_t minimum[I915_MAX_PLANES];
 	uint16_t y_minimum[I915_MAX_PLANES];
 	unsigned int total_data_rate;
-	int plane;
 
-	skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, alloc);
+	skl_ddb_get_pipe_allocation_limits(dev, cstate, config, alloc);
 	alloc_size = skl_ddb_entry_size(alloc);
 	if (alloc_size == 0) {
 		memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
@@ -2914,17 +2929,20 @@
 	alloc->end -= cursor_blocks;
 
 	/* 1. Allocate the mininum required blocks for each active plane */
-	for_each_plane(dev_priv, pipe, plane) {
-		const struct intel_plane_wm_parameters *p;
+	for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+		struct drm_plane *plane = &intel_plane->base;
+		struct drm_framebuffer *fb = plane->state->fb;
+		int id = skl_wm_plane_id(intel_plane);
 
-		p = &params->plane[plane];
-		if (!p->enabled)
+		if (fb == NULL)
+			continue;
+		if (plane->type == DRM_PLANE_TYPE_CURSOR)
 			continue;
 
-		minimum[plane] = 8;
-		alloc_size -= minimum[plane];
-		y_minimum[plane] = p->y_bytes_per_pixel ? 8 : 0;
-		alloc_size -= y_minimum[plane];
+		minimum[id] = 8;
+		alloc_size -= minimum[id];
+		y_minimum[id] = (fb->pixel_format == DRM_FORMAT_NV12) ? 8 : 0;
+		alloc_size -= y_minimum[id];
 	}
 
 	/*
@@ -2933,45 +2951,50 @@
 	 *
 	 * FIXME: we may not allocate every single block here.
 	 */
-	total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params);
+	total_data_rate = skl_get_total_relative_data_rate(cstate);
 
 	start = alloc->start;
-	for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
-		const struct intel_plane_wm_parameters *p;
+	for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+		struct drm_plane *plane = &intel_plane->base;
+		struct drm_plane_state *pstate = intel_plane->base.state;
 		unsigned int data_rate, y_data_rate;
 		uint16_t plane_blocks, y_plane_blocks = 0;
+		int id = skl_wm_plane_id(intel_plane);
 
-		p = &params->plane[plane];
-		if (!p->enabled)
+		if (pstate->fb == NULL)
+			continue;
+		if (plane->type == DRM_PLANE_TYPE_CURSOR)
 			continue;
 
-		data_rate = skl_plane_relative_data_rate(p, 0);
+		data_rate = skl_plane_relative_data_rate(cstate, pstate, 0);
 
 		/*
 		 * allocation for (packed formats) or (uv-plane part of planar format):
 		 * promote the expression to 64 bits to avoid overflowing, the
 		 * result is < available as data_rate / total_data_rate < 1
 		 */
-		plane_blocks = minimum[plane];
+		plane_blocks = minimum[id];
 		plane_blocks += div_u64((uint64_t)alloc_size * data_rate,
 					total_data_rate);
 
-		ddb->plane[pipe][plane].start = start;
-		ddb->plane[pipe][plane].end = start + plane_blocks;
+		ddb->plane[pipe][id].start = start;
+		ddb->plane[pipe][id].end = start + plane_blocks;
 
 		start += plane_blocks;
 
 		/*
 		 * allocation for y_plane part of planar format:
 		 */
-		if (p->y_bytes_per_pixel) {
-			y_data_rate = skl_plane_relative_data_rate(p, 1);
-			y_plane_blocks = y_minimum[plane];
+		if (pstate->fb->pixel_format == DRM_FORMAT_NV12) {
+			y_data_rate = skl_plane_relative_data_rate(cstate,
+								   pstate,
+								   1);
+			y_plane_blocks = y_minimum[id];
 			y_plane_blocks += div_u64((uint64_t)alloc_size * y_data_rate,
 						total_data_rate);
 
-			ddb->y_plane[pipe][plane].start = start;
-			ddb->y_plane[pipe][plane].end = start + y_plane_blocks;
+			ddb->y_plane[pipe][id].start = start;
+			ddb->y_plane[pipe][id].end = start + y_plane_blocks;
 
 			start += y_plane_blocks;
 		}
@@ -3041,104 +3064,27 @@
 	struct drm_device *dev = intel_crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	const struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
-	enum pipe pipe = intel_crtc->pipe;
 
-	if (memcmp(new_ddb->plane[pipe], cur_ddb->plane[pipe],
-		   sizeof(new_ddb->plane[pipe])))
-		return true;
-
-	if (memcmp(&new_ddb->plane[pipe][PLANE_CURSOR], &cur_ddb->plane[pipe][PLANE_CURSOR],
-		    sizeof(new_ddb->plane[pipe][PLANE_CURSOR])))
+	/*
+	 * If ddb allocation of pipes changed, it may require recalculation of
+	 * watermarks
+	 */
+	if (memcmp(new_ddb->pipe, cur_ddb->pipe, sizeof(new_ddb->pipe)))
 		return true;
 
 	return false;
 }
 
-static void skl_compute_wm_global_parameters(struct drm_device *dev,
-					     struct intel_wm_config *config)
-{
-	struct drm_crtc *crtc;
-	struct drm_plane *plane;
-
-	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
-		config->num_pipes_active += to_intel_crtc(crtc)->active;
-
-	/* FIXME: I don't think we need those two global parameters on SKL */
-	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-		struct intel_plane *intel_plane = to_intel_plane(plane);
-
-		config->sprites_enabled |= intel_plane->wm.enabled;
-		config->sprites_scaled |= intel_plane->wm.scaled;
-	}
-}
-
-static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc,
-					   struct skl_pipe_wm_parameters *p)
-{
-	struct drm_device *dev = crtc->dev;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	struct drm_plane *plane;
-	struct drm_framebuffer *fb;
-	int i = 1; /* Index for sprite planes start */
-
-	p->active = intel_crtc->active;
-	if (p->active) {
-		p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal;
-		p->pixel_rate = skl_pipe_pixel_rate(intel_crtc->config);
-
-		fb = crtc->primary->state->fb;
-		/* For planar: Bpp is for uv plane, y_Bpp is for y plane */
-		if (fb) {
-			p->plane[0].enabled = true;
-			p->plane[0].bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ?
-				drm_format_plane_cpp(fb->pixel_format, 1) :
-				drm_format_plane_cpp(fb->pixel_format, 0);
-			p->plane[0].y_bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ?
-				drm_format_plane_cpp(fb->pixel_format, 0) : 0;
-			p->plane[0].tiling = fb->modifier[0];
-		} else {
-			p->plane[0].enabled = false;
-			p->plane[0].bytes_per_pixel = 0;
-			p->plane[0].y_bytes_per_pixel = 0;
-			p->plane[0].tiling = DRM_FORMAT_MOD_NONE;
-		}
-		p->plane[0].horiz_pixels = intel_crtc->config->pipe_src_w;
-		p->plane[0].vert_pixels = intel_crtc->config->pipe_src_h;
-		p->plane[0].rotation = crtc->primary->state->rotation;
-
-		fb = crtc->cursor->state->fb;
-		p->plane[PLANE_CURSOR].y_bytes_per_pixel = 0;
-		if (fb) {
-			p->plane[PLANE_CURSOR].enabled = true;
-			p->plane[PLANE_CURSOR].bytes_per_pixel = fb->bits_per_pixel / 8;
-			p->plane[PLANE_CURSOR].horiz_pixels = crtc->cursor->state->crtc_w;
-			p->plane[PLANE_CURSOR].vert_pixels = crtc->cursor->state->crtc_h;
-		} else {
-			p->plane[PLANE_CURSOR].enabled = false;
-			p->plane[PLANE_CURSOR].bytes_per_pixel = 0;
-			p->plane[PLANE_CURSOR].horiz_pixels = 64;
-			p->plane[PLANE_CURSOR].vert_pixels = 64;
-		}
-	}
-
-	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-		struct intel_plane *intel_plane = to_intel_plane(plane);
-
-		if (intel_plane->pipe == pipe &&
-			plane->type == DRM_PLANE_TYPE_OVERLAY)
-			p->plane[i++] = intel_plane->wm;
-	}
-}
-
 static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
-				 struct skl_pipe_wm_parameters *p,
-				 struct intel_plane_wm_parameters *p_params,
+				 struct intel_crtc_state *cstate,
+				 struct intel_plane *intel_plane,
 				 uint16_t ddb_allocation,
 				 int level,
 				 uint16_t *out_blocks, /* out */
 				 uint8_t *out_lines /* out */)
 {
+	struct drm_plane *plane = &intel_plane->base;
+	struct drm_framebuffer *fb = plane->state->fb;
 	uint32_t latency = dev_priv->wm.skl_latency[level];
 	uint32_t method1, method2;
 	uint32_t plane_bytes_per_line, plane_blocks_per_line;
@@ -3146,31 +3092,33 @@
 	uint32_t selected_result;
 	uint8_t bytes_per_pixel;
 
-	if (latency == 0 || !p->active || !p_params->enabled)
+	if (latency == 0 || !cstate->base.active || !fb)
 		return false;
 
-	bytes_per_pixel = p_params->y_bytes_per_pixel ?
-		p_params->y_bytes_per_pixel :
-		p_params->bytes_per_pixel;
-	method1 = skl_wm_method1(p->pixel_rate,
+	bytes_per_pixel = drm_format_plane_cpp(fb->pixel_format, 0);
+	method1 = skl_wm_method1(skl_pipe_pixel_rate(cstate),
 				 bytes_per_pixel,
 				 latency);
-	method2 = skl_wm_method2(p->pixel_rate,
-				 p->pipe_htotal,
-				 p_params->horiz_pixels,
+	method2 = skl_wm_method2(skl_pipe_pixel_rate(cstate),
+				 cstate->base.adjusted_mode.crtc_htotal,
+				 cstate->pipe_src_w,
 				 bytes_per_pixel,
-				 p_params->tiling,
+				 fb->modifier[0],
 				 latency);
 
-	plane_bytes_per_line = p_params->horiz_pixels * bytes_per_pixel;
+	plane_bytes_per_line = cstate->pipe_src_w * bytes_per_pixel;
 	plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512);
 
-	if (p_params->tiling == I915_FORMAT_MOD_Y_TILED ||
-	    p_params->tiling == I915_FORMAT_MOD_Yf_TILED) {
+	if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
+	    fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
 		uint32_t min_scanlines = 4;
 		uint32_t y_tile_minimum;
-		if (intel_rotation_90_or_270(p_params->rotation)) {
-			switch (p_params->bytes_per_pixel) {
+		if (intel_rotation_90_or_270(plane->state->rotation)) {
+			int bpp = (fb->pixel_format == DRM_FORMAT_NV12) ?
+				drm_format_plane_cpp(fb->pixel_format, 1) :
+				drm_format_plane_cpp(fb->pixel_format, 0);
+
+			switch (bpp) {
 			case 1:
 				min_scanlines = 16;
 				break;
@@ -3194,8 +3142,8 @@
 	res_lines = DIV_ROUND_UP(selected_result, plane_blocks_per_line);
 
 	if (level >= 1 && level <= 7) {
-		if (p_params->tiling == I915_FORMAT_MOD_Y_TILED ||
-		    p_params->tiling == I915_FORMAT_MOD_Yf_TILED)
+		if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
+		    fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)
 			res_lines += 4;
 		else
 			res_blocks++;
@@ -3212,84 +3160,80 @@
 
 static void skl_compute_wm_level(const struct drm_i915_private *dev_priv,
 				 struct skl_ddb_allocation *ddb,
-				 struct skl_pipe_wm_parameters *p,
-				 enum pipe pipe,
+				 struct intel_crtc_state *cstate,
 				 int level,
-				 int num_planes,
 				 struct skl_wm_level *result)
 {
+	struct drm_device *dev = dev_priv->dev;
+	struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
+	struct intel_plane *intel_plane;
 	uint16_t ddb_blocks;
-	int i;
+	enum pipe pipe = intel_crtc->pipe;
 
-	for (i = 0; i < num_planes; i++) {
+	for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+		int i = skl_wm_plane_id(intel_plane);
+
 		ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][i]);
 
 		result->plane_en[i] = skl_compute_plane_wm(dev_priv,
-						p, &p->plane[i],
+						cstate,
+						intel_plane,
 						ddb_blocks,
 						level,
 						&result->plane_res_b[i],
 						&result->plane_res_l[i]);
 	}
-
-	ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][PLANE_CURSOR]);
-	result->plane_en[PLANE_CURSOR] = skl_compute_plane_wm(dev_priv, p,
-						 &p->plane[PLANE_CURSOR],
-						 ddb_blocks, level,
-						 &result->plane_res_b[PLANE_CURSOR],
-						 &result->plane_res_l[PLANE_CURSOR]);
 }
 
 static uint32_t
-skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *p)
+skl_compute_linetime_wm(struct intel_crtc_state *cstate)
 {
-	if (!to_intel_crtc(crtc)->active)
+	if (!cstate->base.active)
 		return 0;
 
-	if (WARN_ON(p->pixel_rate == 0))
+	if (WARN_ON(skl_pipe_pixel_rate(cstate) == 0))
 		return 0;
 
-	return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate);
+	return DIV_ROUND_UP(8 * cstate->base.adjusted_mode.crtc_htotal * 1000,
+			    skl_pipe_pixel_rate(cstate));
 }
 
-static void skl_compute_transition_wm(struct drm_crtc *crtc,
-				      struct skl_pipe_wm_parameters *params,
+static void skl_compute_transition_wm(struct intel_crtc_state *cstate,
 				      struct skl_wm_level *trans_wm /* out */)
 {
+	struct drm_crtc *crtc = cstate->base.crtc;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int i;
+	struct intel_plane *intel_plane;
 
-	if (!params->active)
+	if (!cstate->base.active)
 		return;
 
 	/* Until we know more, just disable transition WMs */
-	for (i = 0; i < intel_num_planes(intel_crtc); i++)
+	for_each_intel_plane_on_crtc(crtc->dev, intel_crtc, intel_plane) {
+		int i = skl_wm_plane_id(intel_plane);
+
 		trans_wm->plane_en[i] = false;
-	trans_wm->plane_en[PLANE_CURSOR] = false;
+	}
 }
 
-static void skl_compute_pipe_wm(struct drm_crtc *crtc,
+static void skl_compute_pipe_wm(struct intel_crtc_state *cstate,
 				struct skl_ddb_allocation *ddb,
-				struct skl_pipe_wm_parameters *params,
 				struct skl_pipe_wm *pipe_wm)
 {
-	struct drm_device *dev = crtc->dev;
+	struct drm_device *dev = cstate->base.crtc->dev;
 	const struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int level, max_level = ilk_wm_max_level(dev);
 
 	for (level = 0; level <= max_level; level++) {
-		skl_compute_wm_level(dev_priv, ddb, params, intel_crtc->pipe,
-				     level, intel_num_planes(intel_crtc),
-				     &pipe_wm->wm[level]);
+		skl_compute_wm_level(dev_priv, ddb, cstate,
+				     level, &pipe_wm->wm[level]);
 	}
-	pipe_wm->linetime = skl_compute_linetime_wm(crtc, params);
+	pipe_wm->linetime = skl_compute_linetime_wm(cstate);
 
-	skl_compute_transition_wm(crtc, params, &pipe_wm->trans_wm);
+	skl_compute_transition_wm(cstate, &pipe_wm->trans_wm);
 }
 
 static void skl_compute_wm_results(struct drm_device *dev,
-				   struct skl_pipe_wm_parameters *p,
 				   struct skl_pipe_wm *p_wm,
 				   struct skl_wm_values *r,
 				   struct intel_crtc *intel_crtc)
@@ -3346,7 +3290,8 @@
 	r->wm_linetime[pipe] = p_wm->linetime;
 }
 
-static void skl_ddb_entry_write(struct drm_i915_private *dev_priv, uint32_t reg,
+static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
+				i915_reg_t reg,
 				const struct skl_ddb_entry *entry)
 {
 	if (entry->end)
@@ -3533,28 +3478,25 @@
 }
 
 static bool skl_update_pipe_wm(struct drm_crtc *crtc,
-			       struct skl_pipe_wm_parameters *params,
-			       struct intel_wm_config *config,
 			       struct skl_ddb_allocation *ddb, /* out */
 			       struct skl_pipe_wm *pipe_wm /* out */)
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
 
-	skl_compute_wm_pipe_parameters(crtc, params);
-	skl_allocate_pipe_ddb(crtc, config, params, ddb);
-	skl_compute_pipe_wm(crtc, ddb, params, pipe_wm);
+	skl_allocate_pipe_ddb(cstate, ddb);
+	skl_compute_pipe_wm(cstate, ddb, pipe_wm);
 
-	if (!memcmp(&intel_crtc->wm.skl_active, pipe_wm, sizeof(*pipe_wm)))
+	if (!memcmp(&intel_crtc->wm.active.skl, pipe_wm, sizeof(*pipe_wm)))
 		return false;
 
-	intel_crtc->wm.skl_active = *pipe_wm;
+	intel_crtc->wm.active.skl = *pipe_wm;
 
 	return true;
 }
 
 static void skl_update_other_pipe_wm(struct drm_device *dev,
 				     struct drm_crtc *crtc,
-				     struct intel_wm_config *config,
 				     struct skl_wm_values *r)
 {
 	struct intel_crtc *intel_crtc;
@@ -3575,7 +3517,6 @@
 	 */
 	list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
 				base.head) {
-		struct skl_pipe_wm_parameters params = {};
 		struct skl_pipe_wm pipe_wm = {};
 		bool wm_changed;
 
@@ -3586,7 +3527,6 @@
 			continue;
 
 		wm_changed = skl_update_pipe_wm(&intel_crtc->base,
-						&params, config,
 						&r->ddb, &pipe_wm);
 
 		/*
@@ -3596,7 +3536,7 @@
 		 */
 		WARN_ON(!wm_changed);
 
-		skl_compute_wm_results(dev, &params, &pipe_wm, r, intel_crtc);
+		skl_compute_wm_results(dev, &pipe_wm, r, intel_crtc);
 		r->dirty[intel_crtc->pipe] = true;
 	}
 }
@@ -3626,10 +3566,9 @@
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct skl_pipe_wm_parameters params = {};
 	struct skl_wm_values *results = &dev_priv->wm.skl_results;
-	struct skl_pipe_wm pipe_wm = {};
-	struct intel_wm_config config = {};
+	struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+	struct skl_pipe_wm *pipe_wm = &cstate->wm.optimal.skl;
 
 
 	/* Clear all dirty flags */
@@ -3637,16 +3576,13 @@
 
 	skl_clear_wm(results, intel_crtc->pipe);
 
-	skl_compute_wm_global_parameters(dev, &config);
-
-	if (!skl_update_pipe_wm(crtc, &params, &config,
-				&results->ddb, &pipe_wm))
+	if (!skl_update_pipe_wm(crtc, &results->ddb, pipe_wm))
 		return;
 
-	skl_compute_wm_results(dev, &params, &pipe_wm, results, intel_crtc);
+	skl_compute_wm_results(dev, pipe_wm, results, intel_crtc);
 	results->dirty[intel_crtc->pipe] = true;
 
-	skl_update_other_pipe_wm(dev, crtc, &config, results);
+	skl_update_other_pipe_wm(dev, crtc, results);
 	skl_write_wm_values(dev_priv, results);
 	skl_flush_wm_values(dev_priv, results);
 
@@ -3654,71 +3590,23 @@
 	dev_priv->wm.skl_hw = *results;
 }
 
-static void
-skl_update_sprite_wm(struct drm_plane *plane, struct drm_crtc *crtc,
-		     uint32_t sprite_width, uint32_t sprite_height,
-		     int pixel_size, bool enabled, bool scaled)
+static void ilk_program_watermarks(struct drm_i915_private *dev_priv)
 {
-	struct intel_plane *intel_plane = to_intel_plane(plane);
-	struct drm_framebuffer *fb = plane->state->fb;
-
-	intel_plane->wm.enabled = enabled;
-	intel_plane->wm.scaled = scaled;
-	intel_plane->wm.horiz_pixels = sprite_width;
-	intel_plane->wm.vert_pixels = sprite_height;
-	intel_plane->wm.tiling = DRM_FORMAT_MOD_NONE;
-
-	/* For planar: Bpp is for UV plane, y_Bpp is for Y plane */
-	intel_plane->wm.bytes_per_pixel =
-		(fb && fb->pixel_format == DRM_FORMAT_NV12) ?
-		drm_format_plane_cpp(plane->state->fb->pixel_format, 1) : pixel_size;
-	intel_plane->wm.y_bytes_per_pixel =
-		(fb && fb->pixel_format == DRM_FORMAT_NV12) ?
-		drm_format_plane_cpp(plane->state->fb->pixel_format, 0) : 0;
-
-	/*
-	 * Framebuffer can be NULL on plane disable, but it does not
-	 * matter for watermarks if we assume no tiling in that case.
-	 */
-	if (fb)
-		intel_plane->wm.tiling = fb->modifier[0];
-	intel_plane->wm.rotation = plane->state->rotation;
-
-	skl_update_wm(crtc);
-}
-
-static void ilk_update_wm(struct drm_crtc *crtc)
-{
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_device *dev = dev_priv->dev;
+	struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
 	struct ilk_wm_maximums max;
+	struct intel_wm_config *config = &dev_priv->wm.config;
 	struct ilk_wm_values results = {};
 	enum intel_ddb_partitioning partitioning;
-	struct intel_pipe_wm pipe_wm = {};
-	struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
-	struct intel_wm_config config = {};
 
-	WARN_ON(cstate->base.active != intel_crtc->active);
-
-	intel_compute_pipe_wm(cstate, &pipe_wm);
-
-	if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm)))
-		return;
-
-	intel_crtc->wm.active = pipe_wm;
-
-	ilk_compute_wm_config(dev, &config);
-
-	ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_1_2, &max);
-	ilk_wm_merge(dev, &config, &max, &lp_wm_1_2);
+	ilk_compute_wm_maximums(dev, 1, config, INTEL_DDB_PART_1_2, &max);
+	ilk_wm_merge(dev, config, &max, &lp_wm_1_2);
 
 	/* 5/6 split only in single pipe config on IVB+ */
 	if (INTEL_INFO(dev)->gen >= 7 &&
-	    config.num_pipes_active == 1 && config.sprites_enabled) {
-		ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max);
-		ilk_wm_merge(dev, &config, &max, &lp_wm_5_6);
+	    config->num_pipes_active == 1 && config->sprites_enabled) {
+		ilk_compute_wm_maximums(dev, 1, config, INTEL_DDB_PART_5_6, &max);
+		ilk_wm_merge(dev, config, &max, &lp_wm_5_6);
 
 		best_lp_wm = ilk_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6);
 	} else {
@@ -3733,14 +3621,13 @@
 	ilk_write_wm_values(dev_priv, &results);
 }
 
-static void
-ilk_update_sprite_wm(struct drm_plane *plane,
-		     struct drm_crtc *crtc,
-		     uint32_t sprite_width, uint32_t sprite_height,
-		     int pixel_size, bool enabled, bool scaled)
+static void ilk_update_wm(struct drm_crtc *crtc)
 {
-	struct drm_device *dev = plane->dev;
-	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+
+	WARN_ON(cstate->base.active != intel_crtc->active);
 
 	/*
 	 * IVB workaround: must disable low power watermarks for at least
@@ -3749,10 +3636,14 @@
 	 *
 	 * WaCxSRDisabledForSpriteScaling:ivb
 	 */
-	if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev))
-		intel_wait_for_vblank(dev, intel_plane->pipe);
+	if (cstate->disable_lp_wm) {
+		ilk_disable_lp_wm(crtc->dev);
+		intel_wait_for_vblank(crtc->dev, intel_crtc->pipe);
+	}
 
-	ilk_update_wm(crtc);
+	intel_crtc->wm.active.ilk = cstate->wm.optimal.ilk;
+
+	ilk_program_watermarks(dev_priv);
 }
 
 static void skl_pipe_wm_active_state(uint32_t val,
@@ -3805,7 +3696,8 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct skl_wm_values *hw = &dev_priv->wm.skl_hw;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct skl_pipe_wm *active = &intel_crtc->wm.skl_active;
+	struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+	struct skl_pipe_wm *active = &cstate->wm.optimal.skl;
 	enum pipe pipe = intel_crtc->pipe;
 	int level, i, max_level;
 	uint32_t temp;
@@ -3849,6 +3741,8 @@
 
 	temp = hw->plane_trans[pipe][PLANE_CURSOR];
 	skl_pipe_wm_active_state(temp, active, true, true, i, 0);
+
+	intel_crtc->wm.active.skl = *active;
 }
 
 void skl_wm_get_hw_state(struct drm_device *dev)
@@ -3868,9 +3762,10 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct ilk_wm_values *hw = &dev_priv->wm.hw;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_pipe_wm *active = &intel_crtc->wm.active;
+	struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+	struct intel_pipe_wm *active = &cstate->wm.optimal.ilk;
 	enum pipe pipe = intel_crtc->pipe;
-	static const unsigned int wm0_pipe_reg[] = {
+	static const i915_reg_t wm0_pipe_reg[] = {
 		[PIPE_A] = WM0_PIPEA_ILK,
 		[PIPE_B] = WM0_PIPEB_ILK,
 		[PIPE_C] = WM0_PIPEC_IVB,
@@ -3907,6 +3802,8 @@
 		for (level = 0; level <= max_level; level++)
 			active->wm[level].enable = true;
 	}
+
+	intel_crtc->wm.active.ilk = *active;
 }
 
 #define _FW_WM(value, plane) \
@@ -4132,21 +4029,6 @@
 		dev_priv->display.update_wm(crtc);
 }
 
-void intel_update_sprite_watermarks(struct drm_plane *plane,
-				    struct drm_crtc *crtc,
-				    uint32_t sprite_width,
-				    uint32_t sprite_height,
-				    int pixel_size,
-				    bool enabled, bool scaled)
-{
-	struct drm_i915_private *dev_priv = plane->dev->dev_private;
-
-	if (dev_priv->display.update_sprite_wm)
-		dev_priv->display.update_sprite_wm(plane, crtc,
-						   sprite_width, sprite_height,
-						   pixel_size, enabled, scaled);
-}
-
 /**
  * Lock protecting IPS related data structures
  */
@@ -4414,7 +4296,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	/* WaGsvDisableTurbo: Workaround to disable turbo on BXT A* */
-	if (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0))
+	if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
 		return;
 
 	WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
@@ -4689,7 +4571,8 @@
 	dev_priv->rps.max_freq		= dev_priv->rps.rp0_freq;
 
 	dev_priv->rps.efficient_freq = dev_priv->rps.rp1_freq;
-	if (IS_HASWELL(dev) || IS_BROADWELL(dev) || IS_SKYLAKE(dev)) {
+	if (IS_HASWELL(dev) || IS_BROADWELL(dev) ||
+	    IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
 		ret = sandybridge_pcode_read(dev_priv,
 					HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL,
 					&ddcc_status);
@@ -4701,7 +4584,7 @@
 					dev_priv->rps.max_freq);
 	}
 
-	if (IS_SKYLAKE(dev)) {
+	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
 		/* Store the frequency values in 16.66 MHZ units, which is
 		   the natural hardware unit for SKL */
 		dev_priv->rps.rp0_freq *= GEN9_FREQ_SCALER;
@@ -4738,7 +4621,7 @@
 	gen6_init_rps_frequencies(dev);
 
 	/* WaGsvDisableTurbo: Workaround to disable turbo on BXT A* */
-	if (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) {
+	if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
 		intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 		return;
 	}
@@ -4806,8 +4689,8 @@
 	DRM_INFO("RC6 %s\n", (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ?
 			"on" : "off");
 	/* WaRsUseTimeoutMode */
-	if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_D0) ||
-	    (IS_BROXTON(dev) && INTEL_REVID(dev) <= BXT_REVID_A0)) {
+	if (IS_SKL_REVID(dev, 0, SKL_REVID_D0) ||
+	    IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
 		I915_WRITE(GEN6_RC6_THRESHOLD, 625); /* 800us */
 		I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE |
 			   GEN7_RC_CTL_TO_MODE |
@@ -5055,7 +4938,7 @@
 	/* convert DDR frequency from units of 266.6MHz to bandwidth */
 	min_ring_freq = mult_frac(min_ring_freq, 8, 3);
 
-	if (IS_SKYLAKE(dev)) {
+	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
 		/* Convert GT frequency to 50 HZ units */
 		min_gpu_freq = dev_priv->rps.min_freq / GEN9_FREQ_SCALER;
 		max_gpu_freq = dev_priv->rps.max_freq / GEN9_FREQ_SCALER;
@@ -5073,7 +4956,7 @@
 		int diff = max_gpu_freq - gpu_freq;
 		unsigned int ia_freq = 0, ring_freq = 0;
 
-		if (IS_SKYLAKE(dev)) {
+		if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
 			/*
 			 * ring_freq = 2 * GT. ring_freq is in 100MHz units
 			 * No floor required for ring frequency on SKL.
@@ -6201,7 +6084,7 @@
 	} else if (INTEL_INFO(dev)->gen >= 9) {
 		gen9_enable_rc6(dev);
 		gen9_enable_rps(dev);
-		if (IS_SKYLAKE(dev))
+		if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
 			__gen6_update_ring_freq(dev);
 	} else if (IS_BROADWELL(dev)) {
 		gen8_enable_rps(dev);
@@ -7057,7 +6940,6 @@
 			dev_priv->display.init_clock_gating =
 				bxt_init_clock_gating;
 		dev_priv->display.update_wm = skl_update_wm;
-		dev_priv->display.update_sprite_wm = skl_update_sprite_wm;
 	} else if (HAS_PCH_SPLIT(dev)) {
 		ilk_setup_wm_latency(dev);
 
@@ -7066,7 +6948,7 @@
 		    (!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] &&
 		     dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
 			dev_priv->display.update_wm = ilk_update_wm;
-			dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
+			dev_priv->display.compute_pipe_wm = ilk_compute_pipe_wm;
 		} else {
 			DRM_DEBUG_KMS("Failed to read display plane latency. "
 				      "Disable CxSR\n");
diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c
index 213581c..bc5ea2a 100644
--- a/drivers/gpu/drm/i915/intel_psr.c
+++ b/drivers/gpu/drm/i915/intel_psr.c
@@ -80,7 +80,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
 	enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
-	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
+	i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
 	uint32_t *data = (uint32_t *) vsc_psr;
 	unsigned int i;
 
@@ -151,13 +151,31 @@
 			   DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE);
 }
 
+static i915_reg_t psr_aux_ctl_reg(struct drm_i915_private *dev_priv,
+				       enum port port)
+{
+	if (INTEL_INFO(dev_priv)->gen >= 9)
+		return DP_AUX_CH_CTL(port);
+	else
+		return EDP_PSR_AUX_CTL;
+}
+
+static i915_reg_t psr_aux_data_reg(struct drm_i915_private *dev_priv,
+					enum port port, int index)
+{
+	if (INTEL_INFO(dev_priv)->gen >= 9)
+		return DP_AUX_CH_DATA(port, index);
+	else
+		return EDP_PSR_AUX_DATA(index);
+}
+
 static void hsw_psr_enable_sink(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
 	struct drm_device *dev = dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	uint32_t aux_clock_divider;
-	uint32_t aux_data_reg, aux_ctl_reg;
+	i915_reg_t aux_ctl_reg;
 	int precharge = 0x3;
 	static const uint8_t aux_msg[] = {
 		[0] = DP_AUX_NATIVE_WRITE << 4,
@@ -166,6 +184,7 @@
 		[3] = 1 - 1,
 		[4] = DP_SET_POWER_D0,
 	};
+	enum port port = dig_port->port;
 	int i;
 
 	BUILD_BUG_ON(sizeof(aux_msg) > 20);
@@ -181,14 +200,11 @@
 				DP_SINK_DEVICE_AUX_FRAME_SYNC_CONF,
 				DP_AUX_FRAME_SYNC_ENABLE);
 
-	aux_data_reg = (INTEL_INFO(dev)->gen >= 9) ?
-				DPA_AUX_CH_DATA1 : EDP_PSR_AUX_DATA1(dev);
-	aux_ctl_reg = (INTEL_INFO(dev)->gen >= 9) ?
-				DPA_AUX_CH_CTL : EDP_PSR_AUX_CTL(dev);
+	aux_ctl_reg = psr_aux_ctl_reg(dev_priv, port);
 
 	/* Setup AUX registers */
 	for (i = 0; i < sizeof(aux_msg); i += 4)
-		I915_WRITE(aux_data_reg + i,
+		I915_WRITE(psr_aux_data_reg(dev_priv, port, i >> 2),
 			   intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i));
 
 	if (INTEL_INFO(dev)->gen >= 9) {
@@ -267,16 +283,11 @@
 	const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES;
 
 	if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) {
-		/* It doesn't mean we shouldn't send TPS patters, so let's
-		   send the minimal TP1 possible and skip TP2. */
-		val |= EDP_PSR_TP1_TIME_100us;
-		val |= EDP_PSR_TP2_TP3_TIME_0us;
-		val |= EDP_PSR_SKIP_AUX_EXIT;
 		/* Sink should be able to train with the 5 or 6 idle patterns */
 		idle_frames += 4;
 	}
 
-	I915_WRITE(EDP_PSR_CTL(dev), val |
+	I915_WRITE(EDP_PSR_CTL, val |
 		   (IS_BROADWELL(dev) ? 0 : link_entry_time) |
 		   max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
 		   idle_frames << EDP_PSR_IDLE_FRAME_SHIFT |
@@ -340,7 +351,7 @@
 	struct drm_device *dev = intel_dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
+	WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
 	WARN_ON(dev_priv->psr.active);
 	lockdep_assert_held(&dev_priv->psr.lock);
 
@@ -404,7 +415,7 @@
 		}
 
 		/* Avoid continuous PSR exit by masking memup and hpd */
-		I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
+		I915_WRITE(EDP_PSR_DEBUG_CTL, EDP_PSR_DEBUG_MASK_MEMUP |
 			   EDP_PSR_DEBUG_MASK_HPD);
 
 		/* Enable PSR on the panel */
@@ -427,6 +438,19 @@
 		vlv_psr_enable_source(intel_dp);
 	}
 
+	/*
+	 * FIXME: Activation should happen immediately since this function
+	 * is just called after pipe is fully trained and enabled.
+	 * However on every platform we face issues when first activation
+	 * follows a modeset so quickly.
+	 *     - On VLV/CHV we get bank screen on first activation
+	 *     - On HSW/BDW we get a recoverable frozen screen until next
+	 *       exit-activate sequence.
+	 */
+	if (INTEL_INFO(dev)->gen < 9)
+		schedule_delayed_work(&dev_priv->psr.work,
+				      msecs_to_jiffies(intel_dp->panel_power_cycle_delay * 5));
+
 	dev_priv->psr.enabled = intel_dp;
 unlock:
 	mutex_unlock(&dev_priv->psr.lock);
@@ -466,17 +490,17 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	if (dev_priv->psr.active) {
-		I915_WRITE(EDP_PSR_CTL(dev),
-			   I915_READ(EDP_PSR_CTL(dev)) & ~EDP_PSR_ENABLE);
+		I915_WRITE(EDP_PSR_CTL,
+			   I915_READ(EDP_PSR_CTL) & ~EDP_PSR_ENABLE);
 
 		/* Wait till PSR is idle */
-		if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev)) &
+		if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL) &
 			       EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10))
 			DRM_ERROR("Timed out waiting for PSR Idle State\n");
 
 		dev_priv->psr.active = false;
 	} else {
-		WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
+		WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
 	}
 }
 
@@ -523,7 +547,7 @@
 	 * and be ready for re-enable.
 	 */
 	if (HAS_DDI(dev_priv->dev)) {
-		if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) &
+		if (wait_for((I915_READ(EDP_PSR_STATUS_CTL) &
 			      EDP_PSR_STATUS_STATE_MASK) == 0, 50)) {
 			DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
 			return;
@@ -566,11 +590,11 @@
 		return;
 
 	if (HAS_DDI(dev)) {
-		val = I915_READ(EDP_PSR_CTL(dev));
+		val = I915_READ(EDP_PSR_CTL);
 
 		WARN_ON(!(val & EDP_PSR_ENABLE));
 
-		I915_WRITE(EDP_PSR_CTL(dev), val & ~EDP_PSR_ENABLE);
+		I915_WRITE(EDP_PSR_CTL, val & ~EDP_PSR_ENABLE);
 	} else {
 		val = I915_READ(VLV_PSRCTL(pipe));
 
@@ -700,7 +724,6 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_crtc *crtc;
 	enum pipe pipe;
-	int delay_ms = HAS_DDI(dev) ? 100 : 500;
 
 	mutex_lock(&dev_priv->psr.lock);
 	if (!dev_priv->psr.enabled) {
@@ -735,8 +758,9 @@
 	}
 
 	if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits)
-		schedule_delayed_work(&dev_priv->psr.work,
-				      msecs_to_jiffies(delay_ms));
+		if (!work_busy(&dev_priv->psr.work.work))
+			schedule_delayed_work(&dev_priv->psr.work,
+					      msecs_to_jiffies(100));
 	mutex_unlock(&dev_priv->psr.lock);
 }
 
@@ -751,6 +775,9 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
+	dev_priv->psr_mmio_base = IS_HASWELL(dev_priv) ?
+		HSW_EDP_PSR_BASE : BDW_EDP_PSR_BASE;
+
 	INIT_DELAYED_WORK(&dev_priv->psr.work, intel_psr_work);
 	mutex_init(&dev_priv->psr.lock);
 }
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 9461a23..57d78f2 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -481,7 +481,7 @@
 {
 	struct drm_device *dev = ring->dev;
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
-	u32 mmio = 0;
+	i915_reg_t mmio;
 
 	/* The ring status page addresses are no longer next to the rest of
 	 * the ring registers as of gen7.
@@ -524,7 +524,7 @@
 	 * invalidating the TLB?
 	 */
 	if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8) {
-		u32 reg = RING_INSTPM(ring->mmio_base);
+		i915_reg_t reg = RING_INSTPM(ring->mmio_base);
 
 		/* ring should be idle before issuing a sync flush*/
 		WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
@@ -733,7 +733,7 @@
 
 	intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(w->count));
 	for (i = 0; i < w->count; i++) {
-		intel_ring_emit(ring, w->reg[i].addr);
+		intel_ring_emit_reg(ring, w->reg[i].addr);
 		intel_ring_emit(ring, w->reg[i].value);
 	}
 	intel_ring_emit(ring, MI_NOOP);
@@ -766,7 +766,8 @@
 }
 
 static int wa_add(struct drm_i915_private *dev_priv,
-		  const u32 addr, const u32 mask, const u32 val)
+		  i915_reg_t addr,
+		  const u32 mask, const u32 val)
 {
 	const u32 idx = dev_priv->workarounds.count;
 
@@ -924,17 +925,15 @@
 	WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
 			  GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC);
 
-	if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) == SKL_REVID_A0 ||
-	    INTEL_REVID(dev) == SKL_REVID_B0)) ||
-	    (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0)) {
-		/* WaDisableDgMirrorFixInHalfSliceChicken5:skl,bxt */
+	/* WaDisableDgMirrorFixInHalfSliceChicken5:skl,bxt */
+	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
+	    IS_BXT_REVID(dev, 0, BXT_REVID_A1))
 		WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5,
 				  GEN9_DG_MIRROR_FIX_ENABLE);
-	}
 
-	if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) ||
-	    (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0)) {
-		/* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */
+	/* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */
+	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
+	    IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
 		WA_SET_BIT_MASKED(GEN7_COMMON_SLICE_CHICKEN1,
 				  GEN9_RHWO_OPTIMIZATION_DISABLE);
 		/*
@@ -944,12 +943,10 @@
 		 */
 	}
 
-	if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) >= SKL_REVID_C0) ||
-	    IS_BROXTON(dev)) {
-		/* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt */
+	/* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt */
+	if (IS_SKL_REVID(dev, SKL_REVID_C0, REVID_FOREVER) || IS_BROXTON(dev))
 		WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7,
 				  GEN9_ENABLE_YV12_BUGFIX);
-	}
 
 	/* Wa4x4STCOptimizationDisable:skl,bxt */
 	/* WaDisablePartialResolveInVc:skl,bxt */
@@ -961,24 +958,22 @@
 			  GEN9_CCS_TLB_PREFETCH_ENABLE);
 
 	/* WaDisableMaskBasedCammingInRCC:skl,bxt */
-	if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) == SKL_REVID_C0) ||
-	    (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0))
+	if (IS_SKL_REVID(dev, SKL_REVID_C0, SKL_REVID_C0) ||
+	    IS_BXT_REVID(dev, 0, BXT_REVID_A1))
 		WA_SET_BIT_MASKED(SLICE_ECO_CHICKEN0,
 				  PIXEL_MASK_CAMMING_DISABLE);
 
 	/* WaForceContextSaveRestoreNonCoherent:skl,bxt */
 	tmp = HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT;
-	if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) == SKL_REVID_F0) ||
-	    (IS_BROXTON(dev) && INTEL_REVID(dev) >= BXT_REVID_B0))
+	if (IS_SKL_REVID(dev, SKL_REVID_F0, SKL_REVID_F0) ||
+	    IS_BXT_REVID(dev, BXT_REVID_B0, REVID_FOREVER))
 		tmp |= HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE;
 	WA_SET_BIT_MASKED(HDC_CHICKEN0, tmp);
 
 	/* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt */
-	if (IS_SKYLAKE(dev) ||
-	    (IS_BROXTON(dev) && INTEL_REVID(dev) <= BXT_REVID_B0)) {
+	if (IS_SKYLAKE(dev) || IS_BXT_REVID(dev, 0, BXT_REVID_B0))
 		WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
 				  GEN8_SAMPLER_POWER_BYPASS_DIS);
-	}
 
 	/* WaDisableSTUnitPowerOptimization:skl,bxt */
 	WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE);
@@ -1038,7 +1033,7 @@
 	if (ret)
 		return ret;
 
-	if (INTEL_REVID(dev) <= SKL_REVID_D0) {
+	if (IS_SKL_REVID(dev, 0, SKL_REVID_D0)) {
 		/* WaDisableHDCInvalidation:skl */
 		I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
 			   BDW_DISABLE_HDC_INVALIDATION);
@@ -1051,23 +1046,23 @@
 	/* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes
 	 * involving this register should also be added to WA batch as required.
 	 */
-	if (INTEL_REVID(dev) <= SKL_REVID_E0)
+	if (IS_SKL_REVID(dev, 0, SKL_REVID_E0))
 		/* WaDisableLSQCROPERFforOCL:skl */
 		I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
 			   GEN8_LQSC_RO_PERF_DIS);
 
 	/* WaEnableGapsTsvCreditFix:skl */
-	if (IS_SKYLAKE(dev) && (INTEL_REVID(dev) >= SKL_REVID_C0)) {
+	if (IS_SKL_REVID(dev, SKL_REVID_C0, REVID_FOREVER)) {
 		I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) |
 					   GEN9_GAPS_TSV_CREDIT_DISABLE));
 	}
 
 	/* WaDisablePowerCompilerClockGating:skl */
-	if (INTEL_REVID(dev) == SKL_REVID_B0)
+	if (IS_SKL_REVID(dev, SKL_REVID_B0, SKL_REVID_B0))
 		WA_SET_BIT_MASKED(HIZ_CHICKEN,
 				  BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE);
 
-	if (INTEL_REVID(dev) <= SKL_REVID_D0) {
+	if (IS_SKL_REVID(dev, 0, SKL_REVID_D0)) {
 		/*
 		 *Use Force Non-Coherent whenever executing a 3D context. This
 		 * is a workaround for a possible hang in the unlikely event
@@ -1078,19 +1073,17 @@
 				  HDC_FORCE_NON_COHERENT);
 	}
 
-	if (INTEL_REVID(dev) == SKL_REVID_C0 ||
-	    INTEL_REVID(dev) == SKL_REVID_D0)
-		/* WaBarrierPerformanceFixDisable:skl */
+	/* WaBarrierPerformanceFixDisable:skl */
+	if (IS_SKL_REVID(dev, SKL_REVID_C0, SKL_REVID_D0))
 		WA_SET_BIT_MASKED(HDC_CHICKEN0,
 				  HDC_FENCE_DEST_SLM_DISABLE |
 				  HDC_BARRIER_PERFORMANCE_DISABLE);
 
 	/* WaDisableSbeCacheDispatchPortSharing:skl */
-	if (INTEL_REVID(dev) <= SKL_REVID_F0) {
+	if (IS_SKL_REVID(dev, 0, SKL_REVID_F0))
 		WA_SET_BIT_MASKED(
 			GEN7_HALF_SLICE_CHICKEN1,
 			GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
-	}
 
 	return skl_tune_iz_hashing(ring);
 }
@@ -1107,11 +1100,11 @@
 
 	/* WaStoreMultiplePTEenable:bxt */
 	/* This is a requirement according to Hardware specification */
-	if (INTEL_REVID(dev) == BXT_REVID_A0)
+	if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
 		I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_TLBPF);
 
 	/* WaSetClckGatingDisableMedia:bxt */
-	if (INTEL_REVID(dev) == BXT_REVID_A0) {
+	if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
 		I915_WRITE(GEN7_MISCCPCTL, (I915_READ(GEN7_MISCCPCTL) &
 					    ~GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE));
 	}
@@ -1121,7 +1114,7 @@
 			  STALL_DOP_GATING_DISABLE);
 
 	/* WaDisableSbeCacheDispatchPortSharing:bxt */
-	if (INTEL_REVID(dev) <= BXT_REVID_B0) {
+	if (IS_BXT_REVID(dev, 0, BXT_REVID_B0)) {
 		WA_SET_BIT_MASKED(
 			GEN7_HALF_SLICE_CHICKEN1,
 			GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
@@ -1319,11 +1312,13 @@
 		return ret;
 
 	for_each_ring(useless, dev_priv, i) {
-		u32 mbox_reg = signaller->semaphore.mbox.signal[i];
-		if (mbox_reg != GEN6_NOSYNC) {
+		i915_reg_t mbox_reg = signaller->semaphore.mbox.signal[i];
+
+		if (i915_mmio_reg_valid(mbox_reg)) {
 			u32 seqno = i915_gem_request_get_seqno(signaller_req);
+
 			intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1));
-			intel_ring_emit(signaller, mbox_reg);
+			intel_ring_emit_reg(signaller, mbox_reg);
 			intel_ring_emit(signaller, seqno);
 		}
 	}
@@ -2004,11 +1999,35 @@
 
 void intel_unpin_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
 {
-	iounmap(ringbuf->virtual_start);
+	if (HAS_LLC(ringbuf->obj->base.dev) && !ringbuf->obj->stolen)
+		vunmap(ringbuf->virtual_start);
+	else
+		iounmap(ringbuf->virtual_start);
 	ringbuf->virtual_start = NULL;
 	i915_gem_object_ggtt_unpin(ringbuf->obj);
 }
 
+static u32 *vmap_obj(struct drm_i915_gem_object *obj)
+{
+	struct sg_page_iter sg_iter;
+	struct page **pages;
+	void *addr;
+	int i;
+
+	pages = drm_malloc_ab(obj->base.size >> PAGE_SHIFT, sizeof(*pages));
+	if (pages == NULL)
+		return NULL;
+
+	i = 0;
+	for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0)
+		pages[i++] = sg_page_iter_page(&sg_iter);
+
+	addr = vmap(pages, i, 0, PAGE_KERNEL);
+	drm_free_large(pages);
+
+	return addr;
+}
+
 int intel_pin_and_map_ringbuffer_obj(struct drm_device *dev,
 				     struct intel_ringbuffer *ringbuf)
 {
@@ -2016,21 +2035,39 @@
 	struct drm_i915_gem_object *obj = ringbuf->obj;
 	int ret;
 
-	ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, PIN_MAPPABLE);
-	if (ret)
-		return ret;
+	if (HAS_LLC(dev_priv) && !obj->stolen) {
+		ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, 0);
+		if (ret)
+			return ret;
 
-	ret = i915_gem_object_set_to_gtt_domain(obj, true);
-	if (ret) {
-		i915_gem_object_ggtt_unpin(obj);
-		return ret;
-	}
+		ret = i915_gem_object_set_to_cpu_domain(obj, true);
+		if (ret) {
+			i915_gem_object_ggtt_unpin(obj);
+			return ret;
+		}
 
-	ringbuf->virtual_start = ioremap_wc(dev_priv->gtt.mappable_base +
-			i915_gem_obj_ggtt_offset(obj), ringbuf->size);
-	if (ringbuf->virtual_start == NULL) {
-		i915_gem_object_ggtt_unpin(obj);
-		return -EINVAL;
+		ringbuf->virtual_start = vmap_obj(obj);
+		if (ringbuf->virtual_start == NULL) {
+			i915_gem_object_ggtt_unpin(obj);
+			return -ENOMEM;
+		}
+	} else {
+		ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, PIN_MAPPABLE);
+		if (ret)
+			return ret;
+
+		ret = i915_gem_object_set_to_gtt_domain(obj, true);
+		if (ret) {
+			i915_gem_object_ggtt_unpin(obj);
+			return ret;
+		}
+
+		ringbuf->virtual_start = ioremap_wc(dev_priv->gtt.mappable_base +
+						    i915_gem_obj_ggtt_offset(obj), ringbuf->size);
+		if (ringbuf->virtual_start == NULL) {
+			i915_gem_object_ggtt_unpin(obj);
+			return -EINVAL;
+		}
 	}
 
 	return 0;
@@ -2070,10 +2107,14 @@
 	int ret;
 
 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
-	if (ring == NULL)
+	if (ring == NULL) {
+		DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n",
+				 engine->name);
 		return ERR_PTR(-ENOMEM);
+	}
 
 	ring->ring = engine;
+	list_add(&ring->link, &engine->buffers);
 
 	ring->size = size;
 	/* Workaround an erratum on the i830 which causes a hang if
@@ -2089,8 +2130,9 @@
 
 	ret = intel_alloc_ringbuffer_obj(engine->dev, ring);
 	if (ret) {
-		DRM_ERROR("Failed to allocate ringbuffer %s: %d\n",
-			  engine->name, ret);
+		DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s: %d\n",
+				 engine->name, ret);
+		list_del(&ring->link);
 		kfree(ring);
 		return ERR_PTR(ret);
 	}
@@ -2102,6 +2144,7 @@
 intel_ringbuffer_free(struct intel_ringbuffer *ring)
 {
 	intel_destroy_ringbuffer_obj(ring);
+	list_del(&ring->link);
 	kfree(ring);
 }
 
@@ -2117,6 +2160,7 @@
 	INIT_LIST_HEAD(&ring->active_list);
 	INIT_LIST_HEAD(&ring->request_list);
 	INIT_LIST_HEAD(&ring->execlist_queue);
+	INIT_LIST_HEAD(&ring->buffers);
 	i915_gem_batch_pool_init(dev, &ring->batch_pool);
 	memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
 
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 49fa41d..5d1eb20 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -100,6 +100,7 @@
 	void __iomem *virtual_start;
 
 	struct intel_engine_cs *ring;
+	struct list_head link;
 
 	u32 head;
 	u32 tail;
@@ -157,6 +158,7 @@
 	u32		mmio_base;
 	struct		drm_device *dev;
 	struct intel_ringbuffer *buffer;
+	struct list_head buffers;
 
 	/*
 	 * A pool of objects to use as shadow copies of client batch buffers
@@ -247,7 +249,7 @@
 				/* our mbox written by others */
 				u32		wait[I915_NUM_RINGS];
 				/* mboxes this ring signals to */
-				u32		signal[I915_NUM_RINGS];
+				i915_reg_t	signal[I915_NUM_RINGS];
 			} mbox;
 			u64		signal_ggtt[I915_NUM_RINGS];
 		};
@@ -441,6 +443,11 @@
 	iowrite32(data, ringbuf->virtual_start + ringbuf->tail);
 	ringbuf->tail += 4;
 }
+static inline void intel_ring_emit_reg(struct intel_engine_cs *ring,
+				       i915_reg_t reg)
+{
+	intel_ring_emit(ring, i915_mmio_reg_offset(reg));
+}
 static inline void intel_ring_advance(struct intel_engine_cs *ring)
 {
 	struct intel_ringbuffer *ringbuf = ring->buffer;
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index 7e23d65..afca6c9 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -49,21 +49,18 @@
  * present for a given platform.
  */
 
-#define GEN9_ENABLE_DC5(dev) 0
-#define SKL_ENABLE_DC6(dev) IS_SKYLAKE(dev)
-
 #define for_each_power_well(i, power_well, domain_mask, power_domains)	\
 	for (i = 0;							\
 	     i < (power_domains)->power_well_count &&			\
 		 ((power_well) = &(power_domains)->power_wells[i]);	\
 	     i++)							\
-		if ((power_well)->domains & (domain_mask))
+		for_each_if ((power_well)->domains & (domain_mask))
 
 #define for_each_power_well_rev(i, power_well, domain_mask, power_domains) \
 	for (i = (power_domains)->power_well_count - 1;			 \
 	     i >= 0 && ((power_well) = &(power_domains)->power_wells[i]);\
 	     i--)							 \
-		if ((power_well)->domains & (domain_mask))
+		for_each_if ((power_well)->domains & (domain_mask))
 
 bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
 				    int power_well_id);
@@ -244,12 +241,6 @@
 		gen8_irq_power_well_post_enable(dev_priv,
 						1 << PIPE_C | 1 << PIPE_B);
 	}
-
-	if (power_well->data == SKL_DISP_PW_1) {
-		if (!dev_priv->power_domains.initializing)
-			intel_prepare_ddi(dev);
-		gen8_irq_power_well_post_enable(dev_priv, 1 << PIPE_A);
-	}
 }
 
 static void hsw_set_power_well(struct drm_i915_private *dev_priv,
@@ -292,58 +283,38 @@
 	BIT(POWER_DOMAIN_TRANSCODER_C) |		\
 	BIT(POWER_DOMAIN_PIPE_B_PANEL_FITTER) |		\
 	BIT(POWER_DOMAIN_PIPE_C_PANEL_FITTER) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_E_2_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_D_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_E_LANES) |		\
 	BIT(POWER_DOMAIN_AUX_B) |                       \
 	BIT(POWER_DOMAIN_AUX_C) |			\
 	BIT(POWER_DOMAIN_AUX_D) |			\
 	BIT(POWER_DOMAIN_AUDIO) |			\
 	BIT(POWER_DOMAIN_VGA) |				\
 	BIT(POWER_DOMAIN_INIT))
-#define SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS (		\
-	SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS |		\
-	BIT(POWER_DOMAIN_PLLS) |			\
-	BIT(POWER_DOMAIN_PIPE_A) |			\
-	BIT(POWER_DOMAIN_TRANSCODER_EDP) |		\
-	BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) |		\
-	BIT(POWER_DOMAIN_AUX_A) |			\
-	BIT(POWER_DOMAIN_INIT))
 #define SKL_DISPLAY_DDI_A_E_POWER_DOMAINS (		\
-	BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_E_2_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_A_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_E_LANES) |		\
 	BIT(POWER_DOMAIN_INIT))
 #define SKL_DISPLAY_DDI_B_POWER_DOMAINS (		\
-	BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |		\
 	BIT(POWER_DOMAIN_INIT))
 #define SKL_DISPLAY_DDI_C_POWER_DOMAINS (		\
-	BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |		\
 	BIT(POWER_DOMAIN_INIT))
 #define SKL_DISPLAY_DDI_D_POWER_DOMAINS (		\
-	BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_D_LANES) |		\
 	BIT(POWER_DOMAIN_INIT))
-#define SKL_DISPLAY_MISC_IO_POWER_DOMAINS (		\
-	SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS |		\
-	BIT(POWER_DOMAIN_PLLS) |			\
+#define SKL_DISPLAY_DC_OFF_POWER_DOMAINS (		\
+	SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS |		\
+	BIT(POWER_DOMAIN_MODESET) |			\
+	BIT(POWER_DOMAIN_AUX_A) |			\
 	BIT(POWER_DOMAIN_INIT))
 #define SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS (		\
-	(POWER_DOMAIN_MASK & ~(SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS |	\
+	(POWER_DOMAIN_MASK & ~(				\
 	SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS |		\
-	SKL_DISPLAY_DDI_A_E_POWER_DOMAINS |		\
-	SKL_DISPLAY_DDI_B_POWER_DOMAINS |		\
-	SKL_DISPLAY_DDI_C_POWER_DOMAINS |		\
-	SKL_DISPLAY_DDI_D_POWER_DOMAINS |		\
-	SKL_DISPLAY_MISC_IO_POWER_DOMAINS)) |		\
+	SKL_DISPLAY_DC_OFF_POWER_DOMAINS)) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 #define BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS (		\
@@ -354,10 +325,8 @@
 	BIT(POWER_DOMAIN_TRANSCODER_C) |		\
 	BIT(POWER_DOMAIN_PIPE_B_PANEL_FITTER) |		\
 	BIT(POWER_DOMAIN_PIPE_C_PANEL_FITTER) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |		\
 	BIT(POWER_DOMAIN_AUX_B) |			\
 	BIT(POWER_DOMAIN_AUX_C) |			\
 	BIT(POWER_DOMAIN_AUDIO) |			\
@@ -369,11 +338,15 @@
 	BIT(POWER_DOMAIN_PIPE_A) |			\
 	BIT(POWER_DOMAIN_TRANSCODER_EDP) |		\
 	BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_A_LANES) |		\
 	BIT(POWER_DOMAIN_AUX_A) |			\
 	BIT(POWER_DOMAIN_PLLS) |			\
 	BIT(POWER_DOMAIN_INIT))
+#define BXT_DISPLAY_DC_OFF_POWER_DOMAINS (		\
+	BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS |		\
+	BIT(POWER_DOMAIN_MODESET) |			\
+	BIT(POWER_DOMAIN_AUX_A) |			\
+	BIT(POWER_DOMAIN_INIT))
 #define BXT_DISPLAY_ALWAYS_ON_POWER_DOMAINS (		\
 	(POWER_DOMAIN_MASK & ~(BXT_DISPLAY_POWERWELL_1_POWER_DOMAINS |	\
 	BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS)) |	\
@@ -417,34 +390,6 @@
 	  */
 }
 
-void bxt_enable_dc9(struct drm_i915_private *dev_priv)
-{
-	uint32_t val;
-
-	assert_can_enable_dc9(dev_priv);
-
-	DRM_DEBUG_KMS("Enabling DC9\n");
-
-	val = I915_READ(DC_STATE_EN);
-	val |= DC_STATE_EN_DC9;
-	I915_WRITE(DC_STATE_EN, val);
-	POSTING_READ(DC_STATE_EN);
-}
-
-void bxt_disable_dc9(struct drm_i915_private *dev_priv)
-{
-	uint32_t val;
-
-	assert_can_disable_dc9(dev_priv);
-
-	DRM_DEBUG_KMS("Disabling DC9\n");
-
-	val = I915_READ(DC_STATE_EN);
-	val &= ~DC_STATE_EN_DC9;
-	I915_WRITE(DC_STATE_EN, val);
-	POSTING_READ(DC_STATE_EN);
-}
-
 static void gen9_set_dc_state_debugmask_memory_up(
 			struct drm_i915_private *dev_priv)
 {
@@ -459,6 +404,62 @@
 	}
 }
 
+static void gen9_set_dc_state(struct drm_i915_private *dev_priv, uint32_t state)
+{
+	uint32_t val;
+	uint32_t mask;
+
+	mask = DC_STATE_EN_UPTO_DC5;
+	if (IS_BROXTON(dev_priv))
+		mask |= DC_STATE_EN_DC9;
+	else
+		mask |= DC_STATE_EN_UPTO_DC6;
+
+	WARN_ON_ONCE(state & ~mask);
+
+	if (i915.enable_dc == 0)
+		state = DC_STATE_DISABLE;
+	else if (i915.enable_dc == 1 && state > DC_STATE_EN_UPTO_DC5)
+		state = DC_STATE_EN_UPTO_DC5;
+
+	if (state & DC_STATE_EN_UPTO_DC5_DC6_MASK)
+		gen9_set_dc_state_debugmask_memory_up(dev_priv);
+
+	val = I915_READ(DC_STATE_EN);
+	DRM_DEBUG_KMS("Setting DC state from %02x to %02x\n",
+		      val & mask, state);
+	val &= ~mask;
+	val |= state;
+	I915_WRITE(DC_STATE_EN, val);
+	POSTING_READ(DC_STATE_EN);
+}
+
+void bxt_enable_dc9(struct drm_i915_private *dev_priv)
+{
+	assert_can_enable_dc9(dev_priv);
+
+	DRM_DEBUG_KMS("Enabling DC9\n");
+
+	gen9_set_dc_state(dev_priv, DC_STATE_EN_DC9);
+}
+
+void bxt_disable_dc9(struct drm_i915_private *dev_priv)
+{
+	assert_can_disable_dc9(dev_priv);
+
+	DRM_DEBUG_KMS("Disabling DC9\n");
+
+	gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
+}
+
+static void assert_csr_loaded(struct drm_i915_private *dev_priv)
+{
+	WARN_ONCE(!I915_READ(CSR_PROGRAM(0)),
+		  "CSR program storage start is NULL\n");
+	WARN_ONCE(!I915_READ(CSR_SSP_BASE), "CSR SSP Base Not fine\n");
+	WARN_ONCE(!I915_READ(CSR_HTP_SKL), "CSR HTP Not fine\n");
+}
+
 static void assert_can_enable_dc5(struct drm_i915_private *dev_priv)
 {
 	struct drm_device *dev = dev_priv->dev;
@@ -479,8 +480,6 @@
 
 static void assert_can_disable_dc5(struct drm_i915_private *dev_priv)
 {
-	bool pg2_enabled = intel_display_power_well_is_enabled(dev_priv,
-					SKL_DISP_PW_2);
 	/*
 	 * During initialization, the firmware may not be loaded yet.
 	 * We still want to make sure that the DC enabling flag is cleared.
@@ -488,40 +487,17 @@
 	if (dev_priv->power_domains.initializing)
 		return;
 
-	WARN_ONCE(!pg2_enabled, "PG2 not enabled to disable DC5.\n");
 	WARN_ONCE(dev_priv->pm.suspended,
 		"Disabling of DC5 while platform is runtime-suspended should never happen.\n");
 }
 
 static void gen9_enable_dc5(struct drm_i915_private *dev_priv)
 {
-	uint32_t val;
-
 	assert_can_enable_dc5(dev_priv);
 
 	DRM_DEBUG_KMS("Enabling DC5\n");
 
-	gen9_set_dc_state_debugmask_memory_up(dev_priv);
-
-	val = I915_READ(DC_STATE_EN);
-	val &= ~DC_STATE_EN_UPTO_DC5_DC6_MASK;
-	val |= DC_STATE_EN_UPTO_DC5;
-	I915_WRITE(DC_STATE_EN, val);
-	POSTING_READ(DC_STATE_EN);
-}
-
-static void gen9_disable_dc5(struct drm_i915_private *dev_priv)
-{
-	uint32_t val;
-
-	assert_can_disable_dc5(dev_priv);
-
-	DRM_DEBUG_KMS("Disabling DC5\n");
-
-	val = I915_READ(DC_STATE_EN);
-	val &= ~DC_STATE_EN_UPTO_DC5;
-	I915_WRITE(DC_STATE_EN, val);
-	POSTING_READ(DC_STATE_EN);
+	gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5);
 }
 
 static void assert_can_enable_dc6(struct drm_i915_private *dev_priv)
@@ -547,40 +523,37 @@
 	if (dev_priv->power_domains.initializing)
 		return;
 
-	assert_csr_loaded(dev_priv);
 	WARN_ONCE(!(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6),
 		  "DC6 already programmed to be disabled.\n");
 }
 
-static void skl_enable_dc6(struct drm_i915_private *dev_priv)
+static void gen9_disable_dc5_dc6(struct drm_i915_private *dev_priv)
 {
-	uint32_t val;
+	assert_can_disable_dc5(dev_priv);
 
+	if (IS_SKYLAKE(dev_priv) && i915.enable_dc != 0 && i915.enable_dc != 1)
+		assert_can_disable_dc6(dev_priv);
+
+	gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
+}
+
+void skl_enable_dc6(struct drm_i915_private *dev_priv)
+{
 	assert_can_enable_dc6(dev_priv);
 
 	DRM_DEBUG_KMS("Enabling DC6\n");
 
-	gen9_set_dc_state_debugmask_memory_up(dev_priv);
+	gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6);
 
-	val = I915_READ(DC_STATE_EN);
-	val &= ~DC_STATE_EN_UPTO_DC5_DC6_MASK;
-	val |= DC_STATE_EN_UPTO_DC6;
-	I915_WRITE(DC_STATE_EN, val);
-	POSTING_READ(DC_STATE_EN);
 }
 
-static void skl_disable_dc6(struct drm_i915_private *dev_priv)
+void skl_disable_dc6(struct drm_i915_private *dev_priv)
 {
-	uint32_t val;
-
 	assert_can_disable_dc6(dev_priv);
 
 	DRM_DEBUG_KMS("Disabling DC6\n");
 
-	val = I915_READ(DC_STATE_EN);
-	val &= ~DC_STATE_EN_UPTO_DC6;
-	I915_WRITE(DC_STATE_EN, val);
-	POSTING_READ(DC_STATE_EN);
+	gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
 }
 
 static void skl_set_power_well(struct drm_i915_private *dev_priv,
@@ -630,20 +603,16 @@
 				!I915_READ(HSW_PWR_WELL_BIOS),
 				"Invalid for power well status to be enabled, unless done by the BIOS, \
 				when request is to disable!\n");
-			if ((GEN9_ENABLE_DC5(dev) || SKL_ENABLE_DC6(dev)) &&
-				power_well->data == SKL_DISP_PW_2) {
-				if (SKL_ENABLE_DC6(dev)) {
-					skl_disable_dc6(dev_priv);
-					/*
-					 * DDI buffer programming unnecessary during driver-load/resume
-					 * as it's already done during modeset initialization then.
-					 * It's also invalid here as encoder list is still uninitialized.
-					 */
-					if (!dev_priv->power_domains.initializing)
-						intel_prepare_ddi(dev);
-				} else {
-					gen9_disable_dc5(dev_priv);
-				}
+			if (power_well->data == SKL_DISP_PW_2) {
+				/*
+				 * DDI buffer programming unnecessary during
+				 * driver-load/resume as it's already done
+				 * during modeset initialization then. It's
+				 * also invalid here as encoder list is still
+				 * uninitialized.
+				 */
+				if (!dev_priv->power_domains.initializing)
+					intel_prepare_ddi(dev);
 			}
 			I915_WRITE(HSW_PWR_WELL_DRIVER, tmp | req_mask);
 		}
@@ -658,34 +627,9 @@
 		}
 	} else {
 		if (enable_requested) {
-			if (IS_SKYLAKE(dev) &&
-				(power_well->data == SKL_DISP_PW_1) &&
-				(intel_csr_load_status_get(dev_priv) == FW_LOADED))
-				DRM_DEBUG_KMS("Not Disabling PW1, dmc will handle\n");
-			else {
-				I915_WRITE(HSW_PWR_WELL_DRIVER,	tmp & ~req_mask);
-				POSTING_READ(HSW_PWR_WELL_DRIVER);
-				DRM_DEBUG_KMS("Disabling %s\n", power_well->name);
-			}
-
-			if ((GEN9_ENABLE_DC5(dev) || SKL_ENABLE_DC6(dev)) &&
-				power_well->data == SKL_DISP_PW_2) {
-				enum csr_state state;
-				/* TODO: wait for a completion event or
-				 * similar here instead of busy
-				 * waiting using wait_for function.
-				 */
-				wait_for((state = intel_csr_load_status_get(dev_priv)) !=
-						FW_UNINITIALIZED, 1000);
-				if (state != FW_LOADED)
-					DRM_DEBUG("CSR firmware not ready (%d)\n",
-							state);
-				else
-					if (SKL_ENABLE_DC6(dev))
-						skl_enable_dc6(dev_priv);
-					else
-						gen9_enable_dc5(dev_priv);
-			}
+			I915_WRITE(HSW_PWR_WELL_DRIVER,	tmp & ~req_mask);
+			POSTING_READ(HSW_PWR_WELL_DRIVER);
+			DRM_DEBUG_KMS("Disabling %s\n", power_well->name);
 		}
 	}
 
@@ -760,6 +704,41 @@
 	skl_set_power_well(dev_priv, power_well, false);
 }
 
+static bool gen9_dc_off_power_well_enabled(struct drm_i915_private *dev_priv,
+					   struct i915_power_well *power_well)
+{
+	return (I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5_DC6_MASK) == 0;
+}
+
+static void gen9_dc_off_power_well_enable(struct drm_i915_private *dev_priv,
+					  struct i915_power_well *power_well)
+{
+	gen9_disable_dc5_dc6(dev_priv);
+}
+
+static void gen9_dc_off_power_well_disable(struct drm_i915_private *dev_priv,
+					   struct i915_power_well *power_well)
+{
+	if (IS_SKYLAKE(dev_priv) && i915.enable_dc != 0 && i915.enable_dc != 1)
+		skl_enable_dc6(dev_priv);
+	else
+		gen9_enable_dc5(dev_priv);
+}
+
+static void gen9_dc_off_power_well_sync_hw(struct drm_i915_private *dev_priv,
+					   struct i915_power_well *power_well)
+{
+	if (power_well->count > 0) {
+		gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
+	} else {
+		if (IS_SKYLAKE(dev_priv) && i915.enable_dc != 0 &&
+		    i915.enable_dc != 1)
+			gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6);
+		else
+			gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5);
+	}
+}
+
 static void i9xx_always_on_power_well_noop(struct drm_i915_private *dev_priv,
 					   struct i915_power_well *power_well)
 {
@@ -974,10 +953,12 @@
 						 int power_well_id)
 {
 	struct i915_power_domains *power_domains = &dev_priv->power_domains;
-	struct i915_power_well *power_well;
 	int i;
 
-	for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) {
+	for (i = 0; i < power_domains->power_well_count; i++) {
+		struct i915_power_well *power_well;
+
+		power_well = &power_domains->power_wells[i];
 		if (power_well->data == power_well_id)
 			return power_well;
 	}
@@ -1458,7 +1439,7 @@
 	for_each_power_well_rev(i, power_well, BIT(domain), power_domains) {
 		WARN_ON(!power_well->count);
 
-		if (!--power_well->count && i915.disable_power_well)
+		if (!--power_well->count)
 			intel_power_well_disable(dev_priv, power_well);
 	}
 
@@ -1470,14 +1451,10 @@
 #define HSW_ALWAYS_ON_POWER_DOMAINS (			\
 	BIT(POWER_DOMAIN_PIPE_A) |			\
 	BIT(POWER_DOMAIN_TRANSCODER_EDP) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |		\
-	BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_A_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |		\
+	BIT(POWER_DOMAIN_PORT_DDI_D_LANES) |		\
 	BIT(POWER_DOMAIN_PORT_CRT) |			\
 	BIT(POWER_DOMAIN_PLLS) |			\
 	BIT(POWER_DOMAIN_AUX_A) |			\
@@ -1501,49 +1478,42 @@
 #define VLV_DISPLAY_POWER_DOMAINS	POWER_DOMAIN_MASK
 
 #define VLV_DPIO_CMN_BC_POWER_DOMAINS (		\
-	BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |	\
-	BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |	\
-	BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |	\
-	BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |	\
+	BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |	\
+	BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |	\
 	BIT(POWER_DOMAIN_PORT_CRT) |		\
 	BIT(POWER_DOMAIN_AUX_B) |		\
 	BIT(POWER_DOMAIN_AUX_C) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 #define VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS (	\
-	BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |	\
-	BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |	\
+	BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |	\
 	BIT(POWER_DOMAIN_AUX_B) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 #define VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS (	\
-	BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |	\
+	BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |	\
 	BIT(POWER_DOMAIN_AUX_B) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 #define VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS (	\
-	BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |	\
-	BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |	\
+	BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |	\
 	BIT(POWER_DOMAIN_AUX_C) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 #define VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS (	\
-	BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |	\
+	BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |	\
 	BIT(POWER_DOMAIN_AUX_C) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 #define CHV_DPIO_CMN_BC_POWER_DOMAINS (		\
-	BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |	\
-	BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |	\
-	BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |	\
-	BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |	\
+	BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |	\
+	BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |	\
 	BIT(POWER_DOMAIN_AUX_B) |		\
 	BIT(POWER_DOMAIN_AUX_C) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 #define CHV_DPIO_CMN_D_POWER_DOMAINS (		\
-	BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |	\
-	BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |	\
+	BIT(POWER_DOMAIN_PORT_DDI_D_LANES) |	\
 	BIT(POWER_DOMAIN_AUX_D) |		\
 	BIT(POWER_DOMAIN_INIT))
 
@@ -1591,6 +1561,13 @@
 	.is_enabled = skl_power_well_enabled,
 };
 
+static const struct i915_power_well_ops gen9_dc_off_power_well_ops = {
+	.sync_hw = gen9_dc_off_power_well_sync_hw,
+	.enable = gen9_dc_off_power_well_enable,
+	.disable = gen9_dc_off_power_well_disable,
+	.is_enabled = gen9_dc_off_power_well_enabled,
+};
+
 static struct i915_power_well hsw_power_wells[] = {
 	{
 		.name = "always-on",
@@ -1646,6 +1623,7 @@
 		.always_on = 1,
 		.domains = VLV_ALWAYS_ON_POWER_DOMAINS,
 		.ops = &i9xx_always_on_power_well_ops,
+		.data = PUNIT_POWER_WELL_ALWAYS_ON,
 	},
 	{
 		.name = "display",
@@ -1747,20 +1725,29 @@
 		.always_on = 1,
 		.domains = SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS,
 		.ops = &i9xx_always_on_power_well_ops,
+		.data = SKL_DISP_PW_ALWAYS_ON,
 	},
 	{
 		.name = "power well 1",
-		.domains = SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS,
+		/* Handled by the DMC firmware */
+		.domains = 0,
 		.ops = &skl_power_well_ops,
 		.data = SKL_DISP_PW_1,
 	},
 	{
 		.name = "MISC IO power well",
-		.domains = SKL_DISPLAY_MISC_IO_POWER_DOMAINS,
+		/* Handled by the DMC firmware */
+		.domains = 0,
 		.ops = &skl_power_well_ops,
 		.data = SKL_DISP_PW_MISC_IO,
 	},
 	{
+		.name = "DC off",
+		.domains = SKL_DISPLAY_DC_OFF_POWER_DOMAINS,
+		.ops = &gen9_dc_off_power_well_ops,
+		.data = SKL_DISP_PW_DC_OFF,
+	},
+	{
 		.name = "power well 2",
 		.domains = SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS,
 		.ops = &skl_power_well_ops,
@@ -1792,6 +1779,34 @@
 	},
 };
 
+void skl_pw1_misc_io_init(struct drm_i915_private *dev_priv)
+{
+	struct i915_power_well *well;
+
+	if (!IS_SKYLAKE(dev_priv))
+		return;
+
+	well = lookup_power_well(dev_priv, SKL_DISP_PW_1);
+	intel_power_well_enable(dev_priv, well);
+
+	well = lookup_power_well(dev_priv, SKL_DISP_PW_MISC_IO);
+	intel_power_well_enable(dev_priv, well);
+}
+
+void skl_pw1_misc_io_fini(struct drm_i915_private *dev_priv)
+{
+	struct i915_power_well *well;
+
+	if (!IS_SKYLAKE(dev_priv))
+		return;
+
+	well = lookup_power_well(dev_priv, SKL_DISP_PW_1);
+	intel_power_well_disable(dev_priv, well);
+
+	well = lookup_power_well(dev_priv, SKL_DISP_PW_MISC_IO);
+	intel_power_well_disable(dev_priv, well);
+}
+
 static struct i915_power_well bxt_power_wells[] = {
 	{
 		.name = "always-on",
@@ -1806,11 +1821,17 @@
 		.data = SKL_DISP_PW_1,
 	},
 	{
+		.name = "DC off",
+		.domains = BXT_DISPLAY_DC_OFF_POWER_DOMAINS,
+		.ops = &gen9_dc_off_power_well_ops,
+		.data = SKL_DISP_PW_DC_OFF,
+	},
+	{
 		.name = "power well 2",
 		.domains = BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS,
 		.ops = &skl_power_well_ops,
 		.data = SKL_DISP_PW_2,
-	}
+	},
 };
 
 static int
@@ -1859,7 +1880,7 @@
 		set_power_wells(power_domains, hsw_power_wells);
 	} else if (IS_BROADWELL(dev_priv->dev)) {
 		set_power_wells(power_domains, bdw_power_wells);
-	} else if (IS_SKYLAKE(dev_priv->dev)) {
+	} else if (IS_SKYLAKE(dev_priv->dev) || IS_KABYLAKE(dev_priv->dev)) {
 		set_power_wells(power_domains, skl_power_wells);
 	} else if (IS_BROXTON(dev_priv->dev)) {
 		set_power_wells(power_domains, bxt_power_wells);
@@ -1874,21 +1895,6 @@
 	return 0;
 }
 
-static void intel_runtime_pm_disable(struct drm_i915_private *dev_priv)
-{
-	struct drm_device *dev = dev_priv->dev;
-	struct device *device = &dev->pdev->dev;
-
-	if (!HAS_RUNTIME_PM(dev))
-		return;
-
-	if (!intel_enable_rc6(dev))
-		return;
-
-	/* Make sure we're not suspended first. */
-	pm_runtime_get_sync(device);
-}
-
 /**
  * intel_power_domains_fini - finalizes the power domain structures
  * @dev_priv: i915 device instance
@@ -1899,15 +1905,17 @@
  */
 void intel_power_domains_fini(struct drm_i915_private *dev_priv)
 {
-	intel_runtime_pm_disable(dev_priv);
-
 	/* The i915.ko module is still not prepared to be loaded when
 	 * the power well is not enabled, so just enable it in case
 	 * we're going to unload/reload. */
 	intel_display_set_init_power(dev_priv, true);
+
+	/* Remove the refcount we took to keep power well support disabled. */
+	if (!i915.disable_power_well)
+		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
 }
 
-static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
+static void intel_power_domains_sync_hw(struct drm_i915_private *dev_priv)
 {
 	struct i915_power_domains *power_domains = &dev_priv->power_domains;
 	struct i915_power_well *power_well;
@@ -1922,6 +1930,47 @@
 	mutex_unlock(&power_domains->lock);
 }
 
+static void skl_display_core_init(struct drm_i915_private *dev_priv,
+				  bool resume)
+{
+	struct i915_power_domains *power_domains = &dev_priv->power_domains;
+	uint32_t val;
+
+	gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
+
+	/* enable PCH reset handshake */
+	val = I915_READ(HSW_NDE_RSTWRN_OPT);
+	I915_WRITE(HSW_NDE_RSTWRN_OPT, val | RESET_PCH_HANDSHAKE_ENABLE);
+
+	/* enable PG1 and Misc I/O */
+	mutex_lock(&power_domains->lock);
+	skl_pw1_misc_io_init(dev_priv);
+	mutex_unlock(&power_domains->lock);
+
+	if (!resume)
+		return;
+
+	skl_init_cdclk(dev_priv);
+
+	if (dev_priv->csr.dmc_payload)
+		intel_csr_load_program(dev_priv);
+}
+
+static void skl_display_core_uninit(struct drm_i915_private *dev_priv)
+{
+	struct i915_power_domains *power_domains = &dev_priv->power_domains;
+
+	gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
+
+	skl_uninit_cdclk(dev_priv);
+
+	/* The spec doesn't call for removing the reset handshake flag */
+	/* disable PG1 and Misc I/O */
+	mutex_lock(&power_domains->lock);
+	skl_pw1_misc_io_fini(dev_priv);
+	mutex_unlock(&power_domains->lock);
+}
+
 static void chv_phy_control_init(struct drm_i915_private *dev_priv)
 {
 	struct i915_power_well *cmn_bc =
@@ -2044,14 +2093,16 @@
  * This function initializes the hardware power domain state and enables all
  * power domains using intel_display_set_init_power().
  */
-void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
+void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
 {
 	struct drm_device *dev = dev_priv->dev;
 	struct i915_power_domains *power_domains = &dev_priv->power_domains;
 
 	power_domains->initializing = true;
 
-	if (IS_CHERRYVIEW(dev)) {
+	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
+		skl_display_core_init(dev_priv, resume);
+	} else if (IS_CHERRYVIEW(dev)) {
 		mutex_lock(&power_domains->lock);
 		chv_phy_control_init(dev_priv);
 		mutex_unlock(&power_domains->lock);
@@ -2063,11 +2114,34 @@
 
 	/* For now, we need the power well to be always enabled. */
 	intel_display_set_init_power(dev_priv, true);
-	intel_power_domains_resume(dev_priv);
+	/* Disable power support if the user asked so. */
+	if (!i915.disable_power_well)
+		intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+	intel_power_domains_sync_hw(dev_priv);
 	power_domains->initializing = false;
 }
 
 /**
+ * intel_power_domains_suspend - suspend power domain state
+ * @dev_priv: i915 device instance
+ *
+ * This function prepares the hardware power domain state before entering
+ * system suspend. It must be paired with intel_power_domains_init_hw().
+ */
+void intel_power_domains_suspend(struct drm_i915_private *dev_priv)
+{
+	if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
+		skl_display_core_uninit(dev_priv);
+
+	/*
+	 * Even if power well support was disabled we still want to disable
+	 * power wells while we are system suspended.
+	 */
+	if (!i915.disable_power_well)
+		intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+}
+
+/**
  * intel_runtime_pm_get - grab a runtime pm reference
  * @dev_priv: i915 device instance
  *
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index c42b636..06679f1 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -74,7 +74,7 @@
 	struct i2c_adapter ddc;
 
 	/* Register for the SDVO device: SDVOB or SDVOC */
-	uint32_t sdvo_reg;
+	i915_reg_t sdvo_reg;
 
 	/* Active outputs controlled by this SDVO output */
 	uint16_t controlled_output;
@@ -120,8 +120,7 @@
 	 */
 	bool is_tv;
 
-	/* On different gens SDVOB is at different places. */
-	bool is_sdvob;
+	enum port port;
 
 	/* This is for current tv format name */
 	int tv_format_index;
@@ -245,7 +244,7 @@
 	u32 bval = val, cval = val;
 	int i;
 
-	if (intel_sdvo->sdvo_reg == PCH_SDVOB) {
+	if (HAS_PCH_SPLIT(dev_priv)) {
 		I915_WRITE(intel_sdvo->sdvo_reg, val);
 		POSTING_READ(intel_sdvo->sdvo_reg);
 		/*
@@ -259,7 +258,7 @@
 		return;
 	}
 
-	if (intel_sdvo->sdvo_reg == GEN3_SDVOB)
+	if (intel_sdvo->port == PORT_B)
 		cval = I915_READ(GEN3_SDVOC);
 	else
 		bval = I915_READ(GEN3_SDVOB);
@@ -422,7 +421,7 @@
 	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_DATA),
 };
 
-#define SDVO_NAME(svdo) ((svdo)->is_sdvob ? "SDVOB" : "SDVOC")
+#define SDVO_NAME(svdo) ((svdo)->port == PORT_B ? "SDVOB" : "SDVOC")
 
 static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,
 				   const void *args, int args_len)
@@ -1282,14 +1281,10 @@
 			sdvox |= SDVO_BORDER_ENABLE;
 	} else {
 		sdvox = I915_READ(intel_sdvo->sdvo_reg);
-		switch (intel_sdvo->sdvo_reg) {
-		case GEN3_SDVOB:
+		if (intel_sdvo->port == PORT_B)
 			sdvox &= SDVOB_PRESERVE_MASK;
-			break;
-		case GEN3_SDVOC:
+		else
 			sdvox &= SDVOC_PRESERVE_MASK;
-			break;
-		}
 		sdvox |= (9 << 19) | SDVO_BORDER_ENABLE;
 	}
 
@@ -1464,12 +1459,23 @@
 	 * matching DP port to be enabled on transcoder A.
 	 */
 	if (HAS_PCH_IBX(dev_priv) && crtc->pipe == PIPE_B) {
+		/*
+		 * We get CPU/PCH FIFO underruns on the other pipe when
+		 * doing the workaround. Sweep them under the rug.
+		 */
+		intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+		intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
+
 		temp &= ~SDVO_PIPE_B_SELECT;
 		temp |= SDVO_ENABLE;
 		intel_sdvo_write_sdvox(intel_sdvo, temp);
 
 		temp &= ~SDVO_ENABLE;
 		intel_sdvo_write_sdvox(intel_sdvo, temp);
+
+		intel_wait_for_vblank_if_active(dev_priv->dev, PIPE_A);
+		intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
+		intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
 	}
 }
 
@@ -2251,7 +2257,7 @@
 {
 	struct sdvo_device_mapping *mapping;
 
-	if (sdvo->is_sdvob)
+	if (sdvo->port == PORT_B)
 		mapping = &(dev_priv->sdvo_mappings[0]);
 	else
 		mapping = &(dev_priv->sdvo_mappings[1]);
@@ -2269,7 +2275,7 @@
 	struct sdvo_device_mapping *mapping;
 	u8 pin;
 
-	if (sdvo->is_sdvob)
+	if (sdvo->port == PORT_B)
 		mapping = &dev_priv->sdvo_mappings[0];
 	else
 		mapping = &dev_priv->sdvo_mappings[1];
@@ -2307,7 +2313,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct sdvo_device_mapping *my_mapping, *other_mapping;
 
-	if (sdvo->is_sdvob) {
+	if (sdvo->port == PORT_B) {
 		my_mapping = &dev_priv->sdvo_mappings[0];
 		other_mapping = &dev_priv->sdvo_mappings[1];
 	} else {
@@ -2332,7 +2338,7 @@
 	/* No SDVO device info is found for another DVO port,
 	 * so use mapping assumption we had before BIOS parsing.
 	 */
-	if (sdvo->is_sdvob)
+	if (sdvo->port == PORT_B)
 		return 0x70;
 	else
 		return 0x72;
@@ -2939,18 +2945,31 @@
 	return i2c_add_adapter(&sdvo->ddc) == 0;
 }
 
-bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
+static void assert_sdvo_port_valid(const struct drm_i915_private *dev_priv,
+				   enum port port)
+{
+	if (HAS_PCH_SPLIT(dev_priv))
+		WARN_ON(port != PORT_B);
+	else
+		WARN_ON(port != PORT_B && port != PORT_C);
+}
+
+bool intel_sdvo_init(struct drm_device *dev,
+		     i915_reg_t sdvo_reg, enum port port)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *intel_encoder;
 	struct intel_sdvo *intel_sdvo;
 	int i;
+
+	assert_sdvo_port_valid(dev_priv, port);
+
 	intel_sdvo = kzalloc(sizeof(*intel_sdvo), GFP_KERNEL);
 	if (!intel_sdvo)
 		return false;
 
 	intel_sdvo->sdvo_reg = sdvo_reg;
-	intel_sdvo->is_sdvob = is_sdvob;
+	intel_sdvo->port = port;
 	intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, intel_sdvo) >> 1;
 	intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo);
 	if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev))
@@ -3000,8 +3019,10 @@
 	 * hotplug lines.
 	 */
 	if (intel_sdvo->hotplug_active) {
-		intel_encoder->hpd_pin =
-			intel_sdvo->is_sdvob ?  HPD_SDVO_B : HPD_SDVO_C;
+		if (intel_sdvo->port == PORT_B)
+			intel_encoder->hpd_pin = HPD_SDVO_B;
+		else
+			intel_encoder->hpd_pin = HPD_SDVO_C;
 	}
 
 	/*
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 56dc132..2b96f33 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -192,10 +192,9 @@
 	const int pipe = intel_plane->pipe;
 	const int plane = intel_plane->plane + 1;
 	u32 plane_ctl, stride_div, stride;
-	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
 	const struct drm_intel_sprite_colorkey *key =
 		&to_intel_plane_state(drm_plane->state)->ckey;
-	unsigned long surf_addr;
+	u32 surf_addr;
 	u32 tile_height, plane_offset, plane_size;
 	unsigned int rotation;
 	int x_offset, y_offset;
@@ -212,10 +211,6 @@
 	rotation = drm_plane->state->rotation;
 	plane_ctl |= skl_plane_ctl_rotation(rotation);
 
-	intel_update_sprite_watermarks(drm_plane, crtc, src_w, src_h,
-				       pixel_size, true,
-				       src_w != crtc_w || src_h != crtc_h);
-
 	stride_div = intel_fb_stride_alignment(dev, fb->modifier[0],
 					       fb->pixel_format);
 
@@ -297,8 +292,6 @@
 
 	I915_WRITE(PLANE_SURF(pipe, plane), 0);
 	POSTING_READ(PLANE_SURF(pipe, plane));
-
-	intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false);
 }
 
 static void
@@ -541,10 +534,6 @@
 	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
 		sprctl |= SPRITE_PIPE_CSC_ENABLE;
 
-	intel_update_sprite_watermarks(plane, crtc, src_w, src_h, pixel_size,
-				       true,
-				       src_w != crtc_w || src_h != crtc_h);
-
 	/* Sizes are 0 based */
 	src_w--;
 	src_h--;
@@ -678,10 +667,6 @@
 	if (IS_GEN6(dev))
 		dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
 
-	intel_update_sprite_watermarks(plane, crtc, src_w, src_h,
-				       pixel_size, true,
-				       src_w != crtc_w || src_h != crtc_h);
-
 	/* Sizes are 0 based */
 	src_w--;
 	src_h--;
@@ -832,8 +817,8 @@
 		hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
 		if (hscale < 0) {
 			DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n");
-			drm_rect_debug_print(src, true);
-			drm_rect_debug_print(dst, false);
+			drm_rect_debug_print("src: ", src, true);
+			drm_rect_debug_print("dst: ", dst, false);
 
 			return hscale;
 		}
@@ -841,8 +826,8 @@
 		vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
 		if (vscale < 0) {
 			DRM_DEBUG_KMS("Vertical scaling factor out of limits\n");
-			drm_rect_debug_print(src, true);
-			drm_rect_debug_print(dst, false);
+			drm_rect_debug_print("src: ", src, true);
+			drm_rect_debug_print("dst: ", dst, false);
 
 			return vscale;
 		}
@@ -938,9 +923,6 @@
 
 	crtc = crtc ? crtc : plane->crtc;
 
-	if (!crtc->state->active)
-		return;
-
 	if (state->visible) {
 		intel_plane->update_plane(plane, crtc, fb,
 					  state->dst.x1, state->dst.y1,
diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
index 43cba12..c2358ba 100644
--- a/drivers/gpu/drm/i915/intel_uncore.c
+++ b/drivers/gpu/drm/i915/intel_uncore.c
@@ -29,19 +29,7 @@
 
 #define FORCEWAKE_ACK_TIMEOUT_MS 50
 
-#define __raw_i915_read8(dev_priv__, reg__) readb((dev_priv__)->regs + (reg__))
-#define __raw_i915_write8(dev_priv__, reg__, val__) writeb(val__, (dev_priv__)->regs + (reg__))
-
-#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__))
-#define __raw_i915_write16(dev_priv__, reg__, val__) writew(val__, (dev_priv__)->regs + (reg__))
-
-#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
-#define __raw_i915_write32(dev_priv__, reg__, val__) writel(val__, (dev_priv__)->regs + (reg__))
-
-#define __raw_i915_read64(dev_priv__, reg__) readq((dev_priv__)->regs + (reg__))
-#define __raw_i915_write64(dev_priv__, reg__, val__) writeq(val__, (dev_priv__)->regs + (reg__))
-
-#define __raw_posting_read(dev_priv__, reg__) (void)__raw_i915_read32(dev_priv__, reg__)
+#define __raw_posting_read(dev_priv__, reg__) (void)__raw_i915_read32((dev_priv__), (reg__))
 
 static const char * const forcewake_domain_names[] = {
 	"render",
@@ -72,7 +60,7 @@
 static inline void
 fw_domain_reset(const struct intel_uncore_forcewake_domain *d)
 {
-	WARN_ON(d->reg_set == 0);
+	WARN_ON(!i915_mmio_reg_valid(d->reg_set));
 	__raw_i915_write32(d->i915, d->reg_set, d->val_reset);
 }
 
@@ -118,7 +106,7 @@
 fw_domain_posting_read(const struct intel_uncore_forcewake_domain *d)
 {
 	/* something from same cacheline, but not from the set register */
-	if (d->reg_post)
+	if (i915_mmio_reg_valid(d->reg_post))
 		__raw_posting_read(d->i915, d->reg_post);
 }
 
@@ -525,8 +513,7 @@
 }
 
 /* We give fast paths for the really cool registers */
-#define NEEDS_FORCE_WAKE(reg) \
-	 ((reg) < 0x40000 && (reg) != FORCEWAKE)
+#define NEEDS_FORCE_WAKE(reg) ((reg) < 0x40000)
 
 #define REG_RANGE(reg, start, end) ((reg) >= (start) && (reg) < (end))
 
@@ -589,7 +576,7 @@
 	REG_RANGE((reg), 0x9400, 0x9800)
 
 #define FORCEWAKE_GEN9_BLITTER_RANGE_OFFSET(reg) \
-	((reg) < 0x40000 &&\
+	((reg) < 0x40000 && \
 	 !FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg) && \
 	 !FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg) && \
 	 !FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg) && \
@@ -605,8 +592,8 @@
 }
 
 static void
-hsw_unclaimed_reg_debug(struct drm_i915_private *dev_priv, u32 reg, bool read,
-			bool before)
+hsw_unclaimed_reg_debug(struct drm_i915_private *dev_priv,
+			i915_reg_t reg, bool read, bool before)
 {
 	const char *op = read ? "reading" : "writing to";
 	const char *when = before ? "before" : "after";
@@ -616,7 +603,7 @@
 
 	if (__raw_i915_read32(dev_priv, FPGA_DBG) & FPGA_DBG_RM_NOCLAIM) {
 		WARN(1, "Unclaimed register detected %s %s register 0x%x\n",
-		     when, op, reg);
+		     when, op, i915_mmio_reg_offset(reg));
 		__raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
 		i915.mmio_debug--; /* Only report the first N failures */
 	}
@@ -649,7 +636,7 @@
 
 #define __gen2_read(x) \
 static u##x \
-gen2_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+gen2_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
 	GEN2_READ_HEADER(x); \
 	val = __raw_i915_read##x(dev_priv, reg); \
 	GEN2_READ_FOOTER; \
@@ -657,7 +644,7 @@
 
 #define __gen5_read(x) \
 static u##x \
-gen5_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+gen5_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
 	GEN2_READ_HEADER(x); \
 	ilk_dummy_write(dev_priv); \
 	val = __raw_i915_read##x(dev_priv, reg); \
@@ -680,6 +667,7 @@
 #undef GEN2_READ_HEADER
 
 #define GEN6_READ_HEADER(x) \
+	u32 offset = i915_mmio_reg_offset(reg); \
 	unsigned long irqflags; \
 	u##x val = 0; \
 	assert_device_not_suspended(dev_priv); \
@@ -714,20 +702,12 @@
 		dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_domains);
 }
 
-#define __vgpu_read(x) \
-static u##x \
-vgpu_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
-	GEN6_READ_HEADER(x); \
-	val = __raw_i915_read##x(dev_priv, reg); \
-	GEN6_READ_FOOTER; \
-}
-
 #define __gen6_read(x) \
 static u##x \
-gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+gen6_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
 	GEN6_READ_HEADER(x); \
 	hsw_unclaimed_reg_debug(dev_priv, reg, true, true); \
-	if (NEEDS_FORCE_WAKE(reg)) \
+	if (NEEDS_FORCE_WAKE(offset)) \
 		__force_wake_get(dev_priv, FORCEWAKE_RENDER); \
 	val = __raw_i915_read##x(dev_priv, reg); \
 	hsw_unclaimed_reg_debug(dev_priv, reg, true, false); \
@@ -736,47 +716,56 @@
 
 #define __vlv_read(x) \
 static u##x \
-vlv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+vlv_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
+	enum forcewake_domains fw_engine = 0; \
 	GEN6_READ_HEADER(x); \
-	if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) \
-		__force_wake_get(dev_priv, FORCEWAKE_RENDER); \
-	else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) \
-		__force_wake_get(dev_priv, FORCEWAKE_MEDIA); \
+	if (!NEEDS_FORCE_WAKE(offset)) \
+		fw_engine = 0; \
+	else if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(offset)) \
+		fw_engine = FORCEWAKE_RENDER; \
+	else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(offset)) \
+		fw_engine = FORCEWAKE_MEDIA; \
+	if (fw_engine) \
+		__force_wake_get(dev_priv, fw_engine); \
 	val = __raw_i915_read##x(dev_priv, reg); \
 	GEN6_READ_FOOTER; \
 }
 
 #define __chv_read(x) \
 static u##x \
-chv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+chv_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
+	enum forcewake_domains fw_engine = 0; \
 	GEN6_READ_HEADER(x); \
-	if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) \
-		__force_wake_get(dev_priv, FORCEWAKE_RENDER); \
-	else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) \
-		__force_wake_get(dev_priv, FORCEWAKE_MEDIA); \
-	else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) \
-		__force_wake_get(dev_priv, \
-				 FORCEWAKE_RENDER | FORCEWAKE_MEDIA); \
+	if (!NEEDS_FORCE_WAKE(offset)) \
+		fw_engine = 0; \
+	else if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(offset)) \
+		fw_engine = FORCEWAKE_RENDER; \
+	else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(offset)) \
+		fw_engine = FORCEWAKE_MEDIA; \
+	else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(offset)) \
+		fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
+	if (fw_engine) \
+		__force_wake_get(dev_priv, fw_engine); \
 	val = __raw_i915_read##x(dev_priv, reg); \
 	GEN6_READ_FOOTER; \
 }
 
 #define SKL_NEEDS_FORCE_WAKE(reg) \
-	 ((reg) < 0x40000 && !FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg))
+	((reg) < 0x40000 && !FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg))
 
 #define __gen9_read(x) \
 static u##x \
-gen9_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+gen9_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
 	enum forcewake_domains fw_engine; \
 	GEN6_READ_HEADER(x); \
 	hsw_unclaimed_reg_debug(dev_priv, reg, true, true); \
-	if (!SKL_NEEDS_FORCE_WAKE(reg)) \
+	if (!SKL_NEEDS_FORCE_WAKE(offset)) \
 		fw_engine = 0; \
-	else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \
+	else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(offset)) \
 		fw_engine = FORCEWAKE_RENDER; \
-	else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) \
+	else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(offset)) \
 		fw_engine = FORCEWAKE_MEDIA; \
-	else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) \
+	else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(offset)) \
 		fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
 	else \
 		fw_engine = FORCEWAKE_BLITTER; \
@@ -787,10 +776,6 @@
 	GEN6_READ_FOOTER; \
 }
 
-__vgpu_read(8)
-__vgpu_read(16)
-__vgpu_read(32)
-__vgpu_read(64)
 __gen9_read(8)
 __gen9_read(16)
 __gen9_read(32)
@@ -812,10 +797,37 @@
 #undef __chv_read
 #undef __vlv_read
 #undef __gen6_read
-#undef __vgpu_read
 #undef GEN6_READ_FOOTER
 #undef GEN6_READ_HEADER
 
+#define VGPU_READ_HEADER(x) \
+	unsigned long irqflags; \
+	u##x val = 0; \
+	assert_device_not_suspended(dev_priv); \
+	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
+
+#define VGPU_READ_FOOTER \
+	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
+	trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \
+	return val
+
+#define __vgpu_read(x) \
+static u##x \
+vgpu_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
+	VGPU_READ_HEADER(x); \
+	val = __raw_i915_read##x(dev_priv, reg); \
+	VGPU_READ_FOOTER; \
+}
+
+__vgpu_read(8)
+__vgpu_read(16)
+__vgpu_read(32)
+__vgpu_read(64)
+
+#undef __vgpu_read
+#undef VGPU_READ_FOOTER
+#undef VGPU_READ_HEADER
+
 #define GEN2_WRITE_HEADER \
 	trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
 	assert_device_not_suspended(dev_priv); \
@@ -824,7 +836,7 @@
 
 #define __gen2_write(x) \
 static void \
-gen2_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
+gen2_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
 	GEN2_WRITE_HEADER; \
 	__raw_i915_write##x(dev_priv, reg, val); \
 	GEN2_WRITE_FOOTER; \
@@ -832,7 +844,7 @@
 
 #define __gen5_write(x) \
 static void \
-gen5_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
+gen5_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
 	GEN2_WRITE_HEADER; \
 	ilk_dummy_write(dev_priv); \
 	__raw_i915_write##x(dev_priv, reg, val); \
@@ -855,6 +867,7 @@
 #undef GEN2_WRITE_HEADER
 
 #define GEN6_WRITE_HEADER \
+	u32 offset = i915_mmio_reg_offset(reg); \
 	unsigned long irqflags; \
 	trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
 	assert_device_not_suspended(dev_priv); \
@@ -865,10 +878,10 @@
 
 #define __gen6_write(x) \
 static void \
-gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
+gen6_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
 	u32 __fifo_ret = 0; \
 	GEN6_WRITE_HEADER; \
-	if (NEEDS_FORCE_WAKE(reg)) { \
+	if (NEEDS_FORCE_WAKE(offset)) { \
 		__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
 	} \
 	__raw_i915_write##x(dev_priv, reg, val); \
@@ -880,10 +893,10 @@
 
 #define __hsw_write(x) \
 static void \
-hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
+hsw_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
 	u32 __fifo_ret = 0; \
 	GEN6_WRITE_HEADER; \
-	if (NEEDS_FORCE_WAKE(reg)) { \
+	if (NEEDS_FORCE_WAKE(offset)) { \
 		__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
 	} \
 	hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \
@@ -896,15 +909,7 @@
 	GEN6_WRITE_FOOTER; \
 }
 
-#define __vgpu_write(x) \
-static void vgpu_write##x(struct drm_i915_private *dev_priv, \
-			  off_t reg, u##x val, bool trace) { \
-	GEN6_WRITE_HEADER; \
-	__raw_i915_write##x(dev_priv, reg, val); \
-	GEN6_WRITE_FOOTER; \
-}
-
-static const u32 gen8_shadowed_regs[] = {
+static const i915_reg_t gen8_shadowed_regs[] = {
 	FORCEWAKE_MT,
 	GEN6_RPNSWREQ,
 	GEN6_RC_VIDEO_FREQ,
@@ -915,11 +920,12 @@
 	/* TODO: Other registers are not yet used */
 };
 
-static bool is_gen8_shadowed(struct drm_i915_private *dev_priv, u32 reg)
+static bool is_gen8_shadowed(struct drm_i915_private *dev_priv,
+			     i915_reg_t reg)
 {
 	int i;
 	for (i = 0; i < ARRAY_SIZE(gen8_shadowed_regs); i++)
-		if (reg == gen8_shadowed_regs[i])
+		if (i915_mmio_reg_equal(reg, gen8_shadowed_regs[i]))
 			return true;
 
 	return false;
@@ -927,10 +933,10 @@
 
 #define __gen8_write(x) \
 static void \
-gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
+gen8_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
 	GEN6_WRITE_HEADER; \
 	hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \
-	if (reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg)) \
+	if (NEEDS_FORCE_WAKE(offset) && !is_gen8_shadowed(dev_priv, reg)) \
 		__force_wake_get(dev_priv, FORCEWAKE_RENDER); \
 	__raw_i915_write##x(dev_priv, reg, val); \
 	hsw_unclaimed_reg_debug(dev_priv, reg, false, false); \
@@ -940,22 +946,25 @@
 
 #define __chv_write(x) \
 static void \
-chv_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
-	bool shadowed = is_gen8_shadowed(dev_priv, reg); \
+chv_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
+	enum forcewake_domains fw_engine = 0; \
 	GEN6_WRITE_HEADER; \
-	if (!shadowed) { \
-		if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) \
-			__force_wake_get(dev_priv, FORCEWAKE_RENDER); \
-		else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) \
-			__force_wake_get(dev_priv, FORCEWAKE_MEDIA); \
-		else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) \
-			__force_wake_get(dev_priv, FORCEWAKE_RENDER | FORCEWAKE_MEDIA); \
-	} \
+	if (!NEEDS_FORCE_WAKE(offset) || \
+	    is_gen8_shadowed(dev_priv, reg)) \
+		fw_engine = 0; \
+	else if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(offset)) \
+		fw_engine = FORCEWAKE_RENDER; \
+	else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(offset)) \
+		fw_engine = FORCEWAKE_MEDIA; \
+	else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(offset)) \
+		fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
+	if (fw_engine) \
+		__force_wake_get(dev_priv, fw_engine); \
 	__raw_i915_write##x(dev_priv, reg, val); \
 	GEN6_WRITE_FOOTER; \
 }
 
-static const u32 gen9_shadowed_regs[] = {
+static const i915_reg_t gen9_shadowed_regs[] = {
 	RING_TAIL(RENDER_RING_BASE),
 	RING_TAIL(GEN6_BSD_RING_BASE),
 	RING_TAIL(VEBOX_RING_BASE),
@@ -968,11 +977,12 @@
 	/* TODO: Other registers are not yet used */
 };
 
-static bool is_gen9_shadowed(struct drm_i915_private *dev_priv, u32 reg)
+static bool is_gen9_shadowed(struct drm_i915_private *dev_priv,
+			     i915_reg_t reg)
 {
 	int i;
 	for (i = 0; i < ARRAY_SIZE(gen9_shadowed_regs); i++)
-		if (reg == gen9_shadowed_regs[i])
+		if (i915_mmio_reg_equal(reg, gen9_shadowed_regs[i]))
 			return true;
 
 	return false;
@@ -980,19 +990,19 @@
 
 #define __gen9_write(x) \
 static void \
-gen9_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, \
+gen9_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, \
 		bool trace) { \
 	enum forcewake_domains fw_engine; \
 	GEN6_WRITE_HEADER; \
 	hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \
-	if (!SKL_NEEDS_FORCE_WAKE(reg) || \
+	if (!SKL_NEEDS_FORCE_WAKE(offset) || \
 	    is_gen9_shadowed(dev_priv, reg)) \
 		fw_engine = 0; \
-	else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \
+	else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(offset)) \
 		fw_engine = FORCEWAKE_RENDER; \
-	else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) \
+	else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(offset)) \
 		fw_engine = FORCEWAKE_MEDIA; \
-	else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) \
+	else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(offset)) \
 		fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
 	else \
 		fw_engine = FORCEWAKE_BLITTER; \
@@ -1024,20 +1034,41 @@
 __gen6_write(16)
 __gen6_write(32)
 __gen6_write(64)
-__vgpu_write(8)
-__vgpu_write(16)
-__vgpu_write(32)
-__vgpu_write(64)
 
 #undef __gen9_write
 #undef __chv_write
 #undef __gen8_write
 #undef __hsw_write
 #undef __gen6_write
-#undef __vgpu_write
 #undef GEN6_WRITE_FOOTER
 #undef GEN6_WRITE_HEADER
 
+#define VGPU_WRITE_HEADER \
+	unsigned long irqflags; \
+	trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
+	assert_device_not_suspended(dev_priv); \
+	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
+
+#define VGPU_WRITE_FOOTER \
+	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags)
+
+#define __vgpu_write(x) \
+static void vgpu_write##x(struct drm_i915_private *dev_priv, \
+			  i915_reg_t reg, u##x val, bool trace) { \
+	VGPU_WRITE_HEADER; \
+	__raw_i915_write##x(dev_priv, reg, val); \
+	VGPU_WRITE_FOOTER; \
+}
+
+__vgpu_write(8)
+__vgpu_write(16)
+__vgpu_write(32)
+__vgpu_write(64)
+
+#undef __vgpu_write
+#undef VGPU_WRITE_FOOTER
+#undef VGPU_WRITE_HEADER
+
 #define ASSIGN_WRITE_MMIO_VFUNCS(x) \
 do { \
 	dev_priv->uncore.funcs.mmio_writeb = x##_write8; \
@@ -1057,7 +1088,8 @@
 
 static void fw_domain_init(struct drm_i915_private *dev_priv,
 			   enum forcewake_domain_id domain_id,
-			   u32 reg_set, u32 reg_ack)
+			   i915_reg_t reg_set,
+			   i915_reg_t reg_ack)
 {
 	struct intel_uncore_forcewake_domain *d;
 
@@ -1087,8 +1119,6 @@
 		d->reg_post = FORCEWAKE_ACK_VLV;
 	else if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv) || IS_GEN8(dev_priv))
 		d->reg_post = ECOBUS;
-	else
-		d->reg_post = 0;
 
 	d->i915 = dev_priv;
 	d->id = domain_id;
@@ -1262,12 +1292,14 @@
 #define GEN_RANGE(l, h) GENMASK(h, l)
 
 static const struct register_whitelist {
-	uint64_t offset;
+	i915_reg_t offset_ldw, offset_udw;
 	uint32_t size;
 	/* supported gens, 0x10 for 4, 0x30 for 4 and 5, etc. */
 	uint32_t gen_bitmask;
 } whitelist[] = {
-	{ RING_TIMESTAMP(RENDER_RING_BASE), 8, GEN_RANGE(4, 9) },
+	{ .offset_ldw = RING_TIMESTAMP(RENDER_RING_BASE),
+	  .offset_udw = RING_TIMESTAMP_UDW(RENDER_RING_BASE),
+	  .size = 8, .gen_bitmask = GEN_RANGE(4, 9) },
 };
 
 int i915_reg_read_ioctl(struct drm_device *dev,
@@ -1277,11 +1309,11 @@
 	struct drm_i915_reg_read *reg = data;
 	struct register_whitelist const *entry = whitelist;
 	unsigned size;
-	u64 offset;
+	i915_reg_t offset_ldw, offset_udw;
 	int i, ret = 0;
 
 	for (i = 0; i < ARRAY_SIZE(whitelist); i++, entry++) {
-		if (entry->offset == (reg->offset & -entry->size) &&
+		if (i915_mmio_reg_offset(entry->offset_ldw) == (reg->offset & -entry->size) &&
 		    (1 << INTEL_INFO(dev)->gen & entry->gen_bitmask))
 			break;
 	}
@@ -1293,27 +1325,28 @@
 	 * be naturally aligned (and those that are not so aligned merely
 	 * limit the available flags for that register).
 	 */
-	offset = entry->offset;
+	offset_ldw = entry->offset_ldw;
+	offset_udw = entry->offset_udw;
 	size = entry->size;
-	size |= reg->offset ^ offset;
+	size |= reg->offset ^ i915_mmio_reg_offset(offset_ldw);
 
 	intel_runtime_pm_get(dev_priv);
 
 	switch (size) {
 	case 8 | 1:
-		reg->val = I915_READ64_2x32(offset, offset+4);
+		reg->val = I915_READ64_2x32(offset_ldw, offset_udw);
 		break;
 	case 8:
-		reg->val = I915_READ64(offset);
+		reg->val = I915_READ64(offset_ldw);
 		break;
 	case 4:
-		reg->val = I915_READ(offset);
+		reg->val = I915_READ(offset_ldw);
 		break;
 	case 2:
-		reg->val = I915_READ16(offset);
+		reg->val = I915_READ16(offset_ldw);
 		break;
 	case 1:
-		reg->val = I915_READ8(offset);
+		reg->val = I915_READ8(offset_ldw);
 		break;
 	default:
 		ret = -EINVAL;
@@ -1470,7 +1503,7 @@
 }
 
 static int wait_for_register(struct drm_i915_private *dev_priv,
-			     const u32 reg,
+			     i915_reg_t reg,
 			     const u32 mask,
 			     const u32 value,
 			     const unsigned long timeout_ms)
diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig
index 2b81a41..35ca4f0 100644
--- a/drivers/gpu/drm/imx/Kconfig
+++ b/drivers/gpu/drm/imx/Kconfig
@@ -10,15 +10,6 @@
 	help
 	  enable i.MX graphics support
 
-config DRM_IMX_FB_HELPER
-	tristate "provide legacy framebuffer /dev/fb0"
-	select DRM_KMS_CMA_HELPER
-	depends on DRM_IMX
-	help
-	  The DRM framework can provide a legacy /dev/fb0 framebuffer
-	  for your device. This is necessary to get a framebuffer console
-	  and also for applications using the legacy framebuffer API
-
 config DRM_IMX_PARALLEL_DISPLAY
 	tristate "Support for parallel displays"
 	select DRM_PANEL
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
index 7b990b4..882cf3d 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -49,8 +49,10 @@
 	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
 };
 
+#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
 static int legacyfb_depth = 16;
 module_param(legacyfb_depth, int, 0444);
+#endif
 
 int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
 {
@@ -60,25 +62,19 @@
 
 static void imx_drm_driver_lastclose(struct drm_device *drm)
 {
-#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
 	struct imx_drm_device *imxdrm = drm->dev_private;
 
 	drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
-#endif
 }
 
 static int imx_drm_driver_unload(struct drm_device *drm)
 {
-#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
 	struct imx_drm_device *imxdrm = drm->dev_private;
-#endif
 
 	drm_kms_helper_poll_fini(drm);
 
-#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
 	if (imxdrm->fbhelper)
 		drm_fbdev_cma_fini(imxdrm->fbhelper);
-#endif
 
 	component_unbind_all(drm->dev, drm);
 
@@ -214,11 +210,9 @@
 
 static void imx_drm_output_poll_changed(struct drm_device *drm)
 {
-#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
 	struct imx_drm_device *imxdrm = drm->dev_private;
 
 	drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
-#endif
 }
 
 static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
@@ -307,7 +301,7 @@
 	 * The fb helper takes copies of key hardware information, so the
 	 * crtcs/connectors/encoders must not change after this point.
 	 */
-#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
 	if (legacyfb_depth != 16 && legacyfb_depth != 32) {
 		dev_warn(drm->dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
 		legacyfb_depth = 16;
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
index 912151c..205b280 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -252,7 +252,7 @@
 				/* mgag200_main.c */
 int mgag200_framebuffer_init(struct drm_device *dev,
 			     struct mga_framebuffer *mfb,
-			     struct drm_mode_fb_cmd2 *mode_cmd,
+			     const struct drm_mode_fb_cmd2 *mode_cmd,
 			     struct drm_gem_object *obj);
 
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c
index b35b5b2..d9b04b0 100644
--- a/drivers/gpu/drm/mgag200/mgag200_fb.c
+++ b/drivers/gpu/drm/mgag200/mgag200_fb.c
@@ -138,7 +138,7 @@
 };
 
 static int mgag200fb_create_object(struct mga_fbdev *afbdev,
-				   struct drm_mode_fb_cmd2 *mode_cmd,
+				   const struct drm_mode_fb_cmd2 *mode_cmd,
 				   struct drm_gem_object **gobj_p)
 {
 	struct drm_device *dev = afbdev->helper.dev;
diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c
index b1a0f56..9147444 100644
--- a/drivers/gpu/drm/mgag200/mgag200_main.c
+++ b/drivers/gpu/drm/mgag200/mgag200_main.c
@@ -29,7 +29,7 @@
 
 int mgag200_framebuffer_init(struct drm_device *dev,
 			     struct mga_framebuffer *gfb,
-			     struct drm_mode_fb_cmd2 *mode_cmd,
+			     const struct drm_mode_fb_cmd2 *mode_cmd,
 			     struct drm_gem_object *obj)
 {
 	int ret;
@@ -47,7 +47,7 @@
 static struct drm_framebuffer *
 mgag200_user_framebuffer_create(struct drm_device *dev,
 				struct drm_file *filp,
-				struct drm_mode_fb_cmd2 *mode_cmd)
+				const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct drm_gem_object *obj;
 	struct mga_framebuffer *mga_fb;
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 3be7a56..9a713b7 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -240,9 +240,9 @@
 struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane);
 const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb);
 struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
-		struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
+		const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
 struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
-		struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd);
+		struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd);
 
 struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev);
 
diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c
index 12171328..a474d6c 100644
--- a/drivers/gpu/drm/msm/msm_fb.c
+++ b/drivers/gpu/drm/msm/msm_fb.c
@@ -138,7 +138,7 @@
 }
 
 struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
-		struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd)
+		struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct drm_gem_object *bos[4] = {0};
 	struct drm_framebuffer *fb;
@@ -168,7 +168,7 @@
 }
 
 struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
-		struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
+		const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
 {
 	struct msm_drm_private *priv = dev->dev_private;
 	struct msm_kms *kms = priv->kms;
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 64c8d93..18676b8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -246,7 +246,7 @@
 int
 nouveau_framebuffer_init(struct drm_device *dev,
 			 struct nouveau_framebuffer *nv_fb,
-			 struct drm_mode_fb_cmd2 *mode_cmd,
+			 const struct drm_mode_fb_cmd2 *mode_cmd,
 			 struct nouveau_bo *nvbo)
 {
 	struct nouveau_display *disp = nouveau_display(dev);
@@ -272,7 +272,7 @@
 static struct drm_framebuffer *
 nouveau_user_framebuffer_create(struct drm_device *dev,
 				struct drm_file *file_priv,
-				struct drm_mode_fb_cmd2 *mode_cmd)
+				const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct nouveau_framebuffer *nouveau_fb;
 	struct drm_gem_object *gem;
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h
index 856abe0..5a57d8b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.h
+++ b/drivers/gpu/drm/nouveau/nouveau_display.h
@@ -23,7 +23,7 @@
 }
 
 int nouveau_framebuffer_init(struct drm_device *, struct nouveau_framebuffer *,
-			     struct drm_mode_fb_cmd2 *, struct nouveau_bo *);
+			     const struct drm_mode_fb_cmd2 *, struct nouveau_bo *);
 
 struct nouveau_page_flip_state {
 	struct list_head head;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index 1e2e9e2..ca77ad0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
@@ -34,7 +34,6 @@
 struct nouveau_fbdev {
 	struct drm_fb_helper helper;
 	struct nouveau_framebuffer nouveau_fb;
-	struct list_head fbdev_list;
 	struct drm_device *dev;
 	unsigned int saved_flags;
 	struct nvif_object surf2d;
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index 5c367aa..130fca7 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -172,9 +172,9 @@
 uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats,
 		uint32_t max_formats, enum omap_color_mode supported_modes);
 struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
-		struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd);
+		struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd);
 struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
-		struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
+		const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
 struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p);
 int omap_framebuffer_pin(struct drm_framebuffer *fb);
 void omap_framebuffer_unpin(struct drm_framebuffer *fb);
@@ -248,7 +248,7 @@
 
 static inline int objects_lookup(struct drm_device *dev,
 		struct drm_file *filp, uint32_t pixel_format,
-		struct drm_gem_object **bos, uint32_t *handles)
+		struct drm_gem_object **bos, const uint32_t *handles)
 {
 	int i, n = drm_format_num_planes(pixel_format);
 
diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c
index 636a1f9..ad202df 100644
--- a/drivers/gpu/drm/omapdrm/omap_fb.c
+++ b/drivers/gpu/drm/omapdrm/omap_fb.c
@@ -364,7 +364,7 @@
 #endif
 
 struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
-		struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd)
+		struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct drm_gem_object *bos[4];
 	struct drm_framebuffer *fb;
@@ -386,7 +386,7 @@
 }
 
 struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
-		struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
+		const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
 {
 	struct omap_framebuffer *omap_fb = NULL;
 	struct drm_framebuffer *fb = NULL;
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 183aea1..cddba07 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -521,7 +521,7 @@
 int
 qxl_framebuffer_init(struct drm_device *dev,
 		     struct qxl_framebuffer *qfb,
-		     struct drm_mode_fb_cmd2 *mode_cmd,
+		     const struct drm_mode_fb_cmd2 *mode_cmd,
 		     struct drm_gem_object *obj)
 {
 	int ret;
@@ -1003,7 +1003,7 @@
 static struct drm_framebuffer *
 qxl_user_framebuffer_create(struct drm_device *dev,
 			    struct drm_file *file_priv,
-			    struct drm_mode_fb_cmd2 *mode_cmd)
+			    const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct drm_gem_object *obj;
 	struct qxl_framebuffer *qxl_fb;
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index 01a8694..6e6b9b1 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -390,7 +390,7 @@
 int
 qxl_framebuffer_init(struct drm_device *dev,
 		     struct qxl_framebuffer *rfb,
-		     struct drm_mode_fb_cmd2 *mode_cmd,
+		     const struct drm_mode_fb_cmd2 *mode_cmd,
 		     struct drm_gem_object *obj);
 void qxl_display_read_client_monitors_config(struct qxl_device *qdev);
 void qxl_send_monitors_config(struct qxl_device *qdev);
diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c
index c4a5526..7136e52 100644
--- a/drivers/gpu/drm/qxl/qxl_fb.c
+++ b/drivers/gpu/drm/qxl/qxl_fb.c
@@ -40,7 +40,6 @@
 struct qxl_fbdev {
 	struct drm_fb_helper helper;
 	struct qxl_framebuffer	qfb;
-	struct list_head	fbdev_list;
 	struct qxl_device	*qdev;
 
 	spinlock_t delayed_ops_lock;
@@ -283,7 +282,7 @@
 }
 
 static int qxlfb_create_pinned_object(struct qxl_fbdev *qfbdev,
-				      struct drm_mode_fb_cmd2 *mode_cmd,
+				      const struct drm_mode_fb_cmd2 *mode_cmd,
 				      struct drm_gem_object **gobj_p)
 {
 	struct qxl_device *qdev = qfbdev->qdev;
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 1eca0ac..b3bb923 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -1331,7 +1331,7 @@
 int
 radeon_framebuffer_init(struct drm_device *dev,
 			struct radeon_framebuffer *rfb,
-			struct drm_mode_fb_cmd2 *mode_cmd,
+			const struct drm_mode_fb_cmd2 *mode_cmd,
 			struct drm_gem_object *obj)
 {
 	int ret;
@@ -1348,7 +1348,7 @@
 static struct drm_framebuffer *
 radeon_user_framebuffer_create(struct drm_device *dev,
 			       struct drm_file *file_priv,
-			       struct drm_mode_fb_cmd2 *mode_cmd)
+			       const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct drm_gem_object *obj;
 	struct radeon_framebuffer *radeon_fb;
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index 26da2f4..adc44bb 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -44,7 +44,6 @@
 struct radeon_fbdev {
 	struct drm_fb_helper helper;
 	struct radeon_framebuffer rfb;
-	struct list_head fbdev_list;
 	struct radeon_device *rdev;
 };
 
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index bba1126..cddd41b 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -934,7 +934,7 @@
 				     u16 *blue, int regno);
 int radeon_framebuffer_init(struct drm_device *dev,
 			     struct radeon_framebuffer *rfb,
-			     struct drm_mode_fb_cmd2 *mode_cmd,
+			     const struct drm_mode_fb_cmd2 *mode_cmd,
 			     struct drm_gem_object *obj);
 
 int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index ca12e8c..43bce69 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -136,7 +136,7 @@
 
 static struct drm_framebuffer *
 rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
-		  struct drm_mode_fb_cmd2 *mode_cmd)
+		  const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct rcar_du_device *rcdu = dev->dev_private;
 	const struct rcar_du_format_info *format;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 002645b..b8ac5911 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -72,7 +72,7 @@
 };
 
 static struct rockchip_drm_fb *
-rockchip_fb_alloc(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd,
+rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd,
 		  struct drm_gem_object **obj, unsigned int num_planes)
 {
 	struct rockchip_drm_fb *rockchip_fb;
@@ -102,7 +102,7 @@
 
 static struct drm_framebuffer *
 rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
-			struct drm_mode_fb_cmd2 *mode_cmd)
+			const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct rockchip_drm_fb *rockchip_fb;
 	struct drm_gem_object *objs[ROCKCHIP_MAX_FB_BUFFER];
@@ -173,7 +173,7 @@
 
 struct drm_framebuffer *
 rockchip_drm_framebuffer_init(struct drm_device *dev,
-			      struct drm_mode_fb_cmd2 *mode_cmd,
+			      const struct drm_mode_fb_cmd2 *mode_cmd,
 			      struct drm_gem_object *obj)
 {
 	struct rockchip_drm_fb *rockchip_fb;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
index 09574d4..2fe47f1 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
@@ -17,7 +17,7 @@
 
 struct drm_framebuffer *
 rockchip_drm_framebuffer_init(struct drm_device *dev,
-			      struct drm_mode_fb_cmd2 *mode_cmd,
+			      const struct drm_mode_fb_cmd2 *mode_cmd,
 			      struct drm_gem_object *obj);
 void rockchip_drm_framebuffer_fini(struct drm_framebuffer *fb);
 
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_kms.c b/drivers/gpu/drm/shmobile/shmob_drm_kms.c
index aaf98ac..388a0fc 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_kms.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_kms.c
@@ -104,7 +104,7 @@
 
 static struct drm_framebuffer *
 shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv,
-		    struct drm_mode_fb_cmd2 *mode_cmd)
+		    const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	const struct shmob_drm_format_info *format;
 
diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig
index 74d9d62..63ebb15 100644
--- a/drivers/gpu/drm/tegra/Kconfig
+++ b/drivers/gpu/drm/tegra/Kconfig
@@ -16,18 +16,6 @@
 
 if DRM_TEGRA
 
-config DRM_TEGRA_FBDEV
-	bool "Enable legacy fbdev support"
-	select DRM_KMS_FB_HELPER
-	select FB_SYS_FILLRECT
-	select FB_SYS_COPYAREA
-	select FB_SYS_IMAGEBLIT
-	default y
-	help
-	  Choose this option if you have a need for the legacy fbdev support.
-	  Note that this support also provides the Linux console on top of
-	  the Tegra modesetting driver.
-
 config DRM_TEGRA_DEBUG
 	bool "NVIDIA Tegra DRM debug support"
 	help
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 159ef51..e0f8277 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -106,7 +106,7 @@
 
 static const struct drm_mode_config_funcs tegra_drm_mode_funcs = {
 	.fb_create = tegra_fb_create,
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
 	.output_poll_changed = tegra_fb_output_poll_changed,
 #endif
 	.atomic_check = drm_atomic_helper_check,
@@ -260,7 +260,7 @@
 
 static void tegra_drm_lastclose(struct drm_device *drm)
 {
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
 	struct tegra_drm *tegra = drm->dev_private;
 
 	tegra_fbdev_restore_mode(tegra->fbdev);
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index ec49275..d88a2d1 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -30,7 +30,7 @@
 	unsigned int num_planes;
 };
 
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
 struct tegra_fbdev {
 	struct drm_fb_helper base;
 	struct tegra_fb *fb;
@@ -46,7 +46,7 @@
 	struct mutex clients_lock;
 	struct list_head clients;
 
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
 	struct tegra_fbdev *fbdev;
 #endif
 
@@ -268,12 +268,12 @@
 			struct tegra_bo_tiling *tiling);
 struct drm_framebuffer *tegra_fb_create(struct drm_device *drm,
 					struct drm_file *file,
-					struct drm_mode_fb_cmd2 *cmd);
+					const struct drm_mode_fb_cmd2 *cmd);
 int tegra_drm_fb_prepare(struct drm_device *drm);
 void tegra_drm_fb_free(struct drm_device *drm);
 int tegra_drm_fb_init(struct drm_device *drm);
 void tegra_drm_fb_exit(struct drm_device *drm);
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
 void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev);
 void tegra_fb_output_poll_changed(struct drm_device *drm);
 #endif
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index 1004075..ede9e94 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -18,7 +18,7 @@
 	return container_of(fb, struct tegra_fb, base);
 }
 
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
 static inline struct tegra_fbdev *to_tegra_fbdev(struct drm_fb_helper *helper)
 {
 	return container_of(helper, struct tegra_fbdev, base);
@@ -92,7 +92,7 @@
 };
 
 static struct tegra_fb *tegra_fb_alloc(struct drm_device *drm,
-				       struct drm_mode_fb_cmd2 *mode_cmd,
+				       const struct drm_mode_fb_cmd2 *mode_cmd,
 				       struct tegra_bo **planes,
 				       unsigned int num_planes)
 {
@@ -131,7 +131,7 @@
 
 struct drm_framebuffer *tegra_fb_create(struct drm_device *drm,
 					struct drm_file *file,
-					struct drm_mode_fb_cmd2 *cmd)
+					const struct drm_mode_fb_cmd2 *cmd)
 {
 	unsigned int hsub, vsub, i;
 	struct tegra_bo *planes[4];
@@ -181,7 +181,7 @@
 	return ERR_PTR(err);
 }
 
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
 static struct fb_ops tegra_fb_ops = {
 	.owner = THIS_MODULE,
 	.fb_fillrect = drm_fb_helper_sys_fillrect,
@@ -370,7 +370,7 @@
 
 int tegra_drm_fb_prepare(struct drm_device *drm)
 {
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
 	struct tegra_drm *tegra = drm->dev_private;
 
 	tegra->fbdev = tegra_fbdev_create(drm);
@@ -383,7 +383,7 @@
 
 void tegra_drm_fb_free(struct drm_device *drm)
 {
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
 	struct tegra_drm *tegra = drm->dev_private;
 
 	tegra_fbdev_free(tegra->fbdev);
@@ -392,7 +392,7 @@
 
 int tegra_drm_fb_init(struct drm_device *drm)
 {
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
 	struct tegra_drm *tegra = drm->dev_private;
 	int err;
 
@@ -407,7 +407,7 @@
 
 void tegra_drm_fb_exit(struct drm_device *drm)
 {
-#ifdef CONFIG_DRM_TEGRA_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
 	struct tegra_drm *tegra = drm->dev_private;
 
 	tegra_fbdev_exit(tegra->fbdev);
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 876cad5..4ddb21e 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -46,7 +46,7 @@
 static struct of_device_id tilcdc_of_match[];
 
 static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev,
-		struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd)
+		struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	return drm_fb_cma_create(dev, file_priv, mode_cmd);
 }
diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h
index 80adbac..4a064ef 100644
--- a/drivers/gpu/drm/udl/udl_drv.h
+++ b/drivers/gpu/drm/udl/udl_drv.h
@@ -108,7 +108,7 @@
 struct drm_framebuffer *
 udl_fb_user_fb_create(struct drm_device *dev,
 		      struct drm_file *file,
-		      struct drm_mode_fb_cmd2 *mode_cmd);
+		      const struct drm_mode_fb_cmd2 *mode_cmd);
 
 int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr,
 		     const char *front, char **urb_buf_ptr,
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
index 62c7b1d..200419d 100644
--- a/drivers/gpu/drm/udl/udl_fb.c
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -33,7 +33,6 @@
 struct udl_fbdev {
 	struct drm_fb_helper helper;
 	struct udl_framebuffer ufb;
-	struct list_head fbdev_list;
 	int fb_count;
 };
 
@@ -456,7 +455,7 @@
 static int
 udl_framebuffer_init(struct drm_device *dev,
 		     struct udl_framebuffer *ufb,
-		     struct drm_mode_fb_cmd2 *mode_cmd,
+		     const struct drm_mode_fb_cmd2 *mode_cmd,
 		     struct udl_gem_object *obj)
 {
 	int ret;
@@ -624,7 +623,7 @@
 struct drm_framebuffer *
 udl_fb_user_fb_create(struct drm_device *dev,
 		   struct drm_file *file,
-		   struct drm_mode_fb_cmd2 *mode_cmd)
+		   const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct drm_gem_object *obj;
 	struct udl_framebuffer *ufb;
diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c
index 578fe0a..8e6044d 100644
--- a/drivers/gpu/drm/virtio/virtgpu_display.c
+++ b/drivers/gpu/drm/virtio/virtgpu_display.c
@@ -215,7 +215,7 @@
 int
 virtio_gpu_framebuffer_init(struct drm_device *dev,
 			    struct virtio_gpu_framebuffer *vgfb,
-			    struct drm_mode_fb_cmd2 *mode_cmd,
+			    const struct drm_mode_fb_cmd2 *mode_cmd,
 			    struct drm_gem_object *obj)
 {
 	int ret;
@@ -465,7 +465,7 @@
 static struct drm_framebuffer *
 virtio_gpu_user_framebuffer_create(struct drm_device *dev,
 				   struct drm_file *file_priv,
-				   struct drm_mode_fb_cmd2 *mode_cmd)
+				   const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct drm_gem_object *obj = NULL;
 	struct virtio_gpu_framebuffer *virtio_gpu_fb;
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index 79f0abe..8f486f4 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -328,7 +328,7 @@
 /* virtio_gpu_display.c */
 int virtio_gpu_framebuffer_init(struct drm_device *dev,
 				struct virtio_gpu_framebuffer *vgfb,
-				struct drm_mode_fb_cmd2 *mode_cmd,
+				const struct drm_mode_fb_cmd2 *mode_cmd,
 				struct drm_gem_object *obj);
 int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev);
 void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev);
diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c
index 6a81e08..2242a80 100644
--- a/drivers/gpu/drm/virtio/virtgpu_fb.c
+++ b/drivers/gpu/drm/virtio/virtgpu_fb.c
@@ -32,7 +32,6 @@
 struct virtio_gpu_fbdev {
 	struct drm_fb_helper           helper;
 	struct virtio_gpu_framebuffer  vgfb;
-	struct list_head	       fbdev_list;
 	struct virtio_gpu_device       *vgdev;
 	struct delayed_work            work;
 };
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 9b4bb9e..27652b0 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -968,7 +968,7 @@
 
 static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
 						 struct drm_file *file_priv,
-						 struct drm_mode_fb_cmd2 *mode_cmd2)
+						 const struct drm_mode_fb_cmd2 *mode_cmd2)
 {
 	struct vmw_private *dev_priv = vmw_priv(dev);
 	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index 7c38bfa..086d8a5 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
@@ -24,7 +24,7 @@
  *   http://www.silabs.com/Support%20Documents/TechnicalDocs/AN495.pdf
  */
 
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/hid.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
@@ -169,8 +169,7 @@
 
 static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct cp2112_device *dev = container_of(chip, struct cp2112_device,
-						 gc);
+	struct cp2112_device *dev = gpiochip_get_data(chip);
 	struct hid_device *hdev = dev->hdev;
 	u8 buf[5];
 	int ret;
@@ -198,8 +197,7 @@
 
 static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct cp2112_device *dev = container_of(chip, struct cp2112_device,
-						 gc);
+	struct cp2112_device *dev = gpiochip_get_data(chip);
 	struct hid_device *hdev = dev->hdev;
 	u8 buf[3];
 	int ret;
@@ -216,8 +214,7 @@
 
 static int cp2112_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct cp2112_device *dev = container_of(chip, struct cp2112_device,
-						 gc);
+	struct cp2112_device *dev = gpiochip_get_data(chip);
 	struct hid_device *hdev = dev->hdev;
 	u8 buf[2];
 	int ret;
@@ -235,8 +232,7 @@
 static int cp2112_gpio_direction_output(struct gpio_chip *chip,
 					unsigned offset, int value)
 {
-	struct cp2112_device *dev = container_of(chip, struct cp2112_device,
-						 gc);
+	struct cp2112_device *dev = gpiochip_get_data(chip);
 	struct hid_device *hdev = dev->hdev;
 	u8 buf[5];
 	int ret;
@@ -1104,9 +1100,9 @@
 	dev->gc.base			= -1;
 	dev->gc.ngpio			= 8;
 	dev->gc.can_sleep		= 1;
-	dev->gc.dev			= &hdev->dev;
+	dev->gc.parent			= &hdev->dev;
 
-	ret = gpiochip_add(&dev->gc);
+	ret = gpiochip_add_data(&dev->gc, dev);
 	if (ret < 0) {
 		hid_err(hdev, "error registering gpio chip\n");
 		goto err_free_i2c;
diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c
index 7386819..68c350c 100644
--- a/drivers/hwmon/sch56xx-common.c
+++ b/drivers/hwmon/sch56xx-common.c
@@ -30,7 +30,6 @@
 #include <linux/watchdog.h>
 #include <linux/miscdevice.h>
 #include <linux/uaccess.h>
-#include <linux/kref.h>
 #include <linux/slab.h>
 #include "sch56xx-common.h"
 
@@ -67,7 +66,6 @@
 struct sch56xx_watchdog_data {
 	u16 addr;
 	struct mutex *io_lock;
-	struct kref kref;
 	struct watchdog_info wdinfo;
 	struct watchdog_device wddev;
 	u8 watchdog_preset;
@@ -258,15 +256,6 @@
  * Watchdog routines
  */
 
-/* Release our data struct when we're unregistered *and*
-   all references to our watchdog device are released */
-static void watchdog_release_resources(struct kref *r)
-{
-	struct sch56xx_watchdog_data *data =
-		container_of(r, struct sch56xx_watchdog_data, kref);
-	kfree(data);
-}
-
 static int watchdog_set_timeout(struct watchdog_device *wddev,
 				unsigned int timeout)
 {
@@ -395,28 +384,12 @@
 	return 0;
 }
 
-static void watchdog_ref(struct watchdog_device *wddev)
-{
-	struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
-
-	kref_get(&data->kref);
-}
-
-static void watchdog_unref(struct watchdog_device *wddev)
-{
-	struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
-
-	kref_put(&data->kref, watchdog_release_resources);
-}
-
 static const struct watchdog_ops watchdog_ops = {
 	.owner		= THIS_MODULE,
 	.start		= watchdog_start,
 	.stop		= watchdog_stop,
 	.ping		= watchdog_trigger,
 	.set_timeout	= watchdog_set_timeout,
-	.ref		= watchdog_ref,
-	.unref		= watchdog_unref,
 };
 
 struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
@@ -448,7 +421,6 @@
 
 	data->addr = addr;
 	data->io_lock = io_lock;
-	kref_init(&data->kref);
 
 	strlcpy(data->wdinfo.identity, "sch56xx watchdog",
 		sizeof(data->wdinfo.identity));
@@ -494,8 +466,7 @@
 void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data)
 {
 	watchdog_unregister_device(&data->wddev);
-	kref_put(&data->kref, watchdog_release_resources);
-	/* Don't touch data after this it may have been free-ed! */
+	kfree(data);
 }
 EXPORT_SYMBOL(sch56xx_watchdog_unregister);
 
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index fec66ad..16b5cc2 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -454,7 +454,7 @@
 		ts->gc.ngpio = 1;
 		ts->gc.label = "AD7879-GPIO";
 		ts->gc.owner = THIS_MODULE;
-		ts->gc.dev = ts->dev;
+		ts->gc.parent = ts->dev;
 
 		ret = gpiochip_add(&ts->gc);
 		if (ret)
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index 17c63ec..e3d3b1a 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -242,7 +242,7 @@
 #ifdef CONFIG_LEDS_PCA9532_GPIO
 static int pca9532_gpio_request_pin(struct gpio_chip *gc, unsigned offset)
 {
-	struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
+	struct pca9532_data *data = gpiochip_get_data(gc);
 	struct pca9532_led *led = &data->leds[offset];
 
 	if (led->type == PCA9532_TYPE_GPIO)
@@ -253,7 +253,7 @@
 
 static void pca9532_gpio_set_value(struct gpio_chip *gc, unsigned offset, int val)
 {
-	struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
+	struct pca9532_data *data = gpiochip_get_data(gc);
 	struct pca9532_led *led = &data->leds[offset];
 
 	if (val)
@@ -266,7 +266,7 @@
 
 static int pca9532_gpio_get_value(struct gpio_chip *gc, unsigned offset)
 {
-	struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
+	struct pca9532_data *data = gpiochip_get_data(gc);
 	unsigned char reg;
 
 	reg = i2c_smbus_read_byte_data(data->client, PCA9532_REG_INPUT(offset));
@@ -315,7 +315,7 @@
 	}
 
 #ifdef CONFIG_LEDS_PCA9532_GPIO
-	if (data->gpio.dev)
+	if (data->gpio.parent)
 		gpiochip_remove(&data->gpio);
 #endif
 
@@ -409,13 +409,13 @@
 		data->gpio.can_sleep = 1;
 		data->gpio.base = pdata->gpio_base;
 		data->gpio.ngpio = data->chip_info->num_leds;
-		data->gpio.dev = &client->dev;
+		data->gpio.parent = &client->dev;
 		data->gpio.owner = THIS_MODULE;
 
-		err = gpiochip_add(&data->gpio);
+		err = gpiochip_add_data(&data->gpio, data);
 		if (err) {
 			/* Use data->gpio.dev as a flag for freeing gpiochip */
-			data->gpio.dev = NULL;
+			data->gpio.parent = NULL;
 			dev_warn(&client->dev, "could not add gpiochip\n");
 		} else {
 			dev_info(&client->dev, "gpios %i...%i\n",
diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c
index edbecc4..c548ea1 100644
--- a/drivers/leds/leds-tca6507.c
+++ b/drivers/leds/leds-tca6507.c
@@ -603,7 +603,7 @@
 static void tca6507_gpio_set_value(struct gpio_chip *gc,
 				   unsigned offset, int val)
 {
-	struct tca6507_chip *tca = container_of(gc, struct tca6507_chip, gpio);
+	struct tca6507_chip *tca = gpiochip_get_data(gc);
 	unsigned long flags;
 
 	spin_lock_irqsave(&tca->lock, flags);
@@ -651,11 +651,11 @@
 	tca->gpio.owner = THIS_MODULE;
 	tca->gpio.direction_output = tca6507_gpio_direction_output;
 	tca->gpio.set = tca6507_gpio_set_value;
-	tca->gpio.dev = &client->dev;
+	tca->gpio.parent = &client->dev;
 #ifdef CONFIG_OF_GPIO
 	tca->gpio.of_node = of_node_get(client->dev.of_node);
 #endif
-	err = gpiochip_add(&tca->gpio);
+	err = gpiochip_add_data(&tca->gpio, tca);
 	if (err) {
 		tca->gpio.ngpio = 0;
 		return err;
diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c
index def6d21..24a457d 100644
--- a/drivers/media/dvb-frontends/cxd2820r_core.c
+++ b/drivers/media/dvb-frontends/cxd2820r_core.c
@@ -722,7 +722,7 @@
 #ifdef CONFIG_GPIOLIB
 		/* add GPIOs */
 		priv->gpio_chip.label = KBUILD_MODNAME;
-		priv->gpio_chip.dev = &priv->i2c->dev;
+		priv->gpio_chip.parent = &priv->i2c->dev;
 		priv->gpio_chip.owner = THIS_MODULE;
 		priv->gpio_chip.direction_output =
 				cxd2820r_gpio_direction_output;
diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c
index bf3e0b2..ec4438e 100644
--- a/drivers/mfd/dm355evm_msp.c
+++ b/drivers/mfd/dm355evm_msp.c
@@ -259,7 +259,7 @@
 	int		i;
 
 	/* GPIO-ish stuff */
-	dm355evm_msp_gpio.dev = &client->dev;
+	dm355evm_msp_gpio.parent = &client->dev;
 	status = gpiochip_add(&dm355evm_msp_gpio);
 	if (status < 0)
 		return status;
diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c
index e4f4a31..c636b5f 100644
--- a/drivers/mfd/htc-egpio.c
+++ b/drivers/mfd/htc-egpio.c
@@ -321,7 +321,7 @@
 		ei->chip[i].dev = &(pdev->dev);
 		chip = &(ei->chip[i].chip);
 		chip->label           = "htc-egpio";
-		chip->dev             = &pdev->dev;
+		chip->parent          = &pdev->dev;
 		chip->owner           = THIS_MODULE;
 		chip->get             = egpio_get;
 		chip->set             = egpio_set;
diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c
index 0c6ff72..bd6b96d 100644
--- a/drivers/mfd/htc-i2cpld.c
+++ b/drivers/mfd/htc-i2cpld.c
@@ -429,7 +429,7 @@
 	/* Setup the GPIO chips */
 	gpio_chip = &(chip->chip_out);
 	gpio_chip->label           = "htcpld-out";
-	gpio_chip->dev             = dev;
+	gpio_chip->parent             = dev;
 	gpio_chip->owner           = THIS_MODULE;
 	gpio_chip->get             = htcpld_chip_get;
 	gpio_chip->set             = htcpld_chip_set;
@@ -440,7 +440,7 @@
 
 	gpio_chip = &(chip->chip_in);
 	gpio_chip->label           = "htcpld-in";
-	gpio_chip->dev             = dev;
+	gpio_chip->parent             = dev;
 	gpio_chip->owner           = THIS_MODULE;
 	gpio_chip->get             = htcpld_chip_get;
 	gpio_chip->set             = NULL;
diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c
index 677a127..83e615e 100644
--- a/drivers/mfd/tps65010.c
+++ b/drivers/mfd/tps65010.c
@@ -638,7 +638,7 @@
 		tps->outmask = board->outmask;
 
 		tps->chip.label = client->name;
-		tps->chip.dev = &client->dev;
+		tps->chip.parent = &client->dev;
 		tps->chip.owner = THIS_MODULE;
 
 		tps->chip.set = tps65010_gpio_set;
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index e0dd83f..bcafe1e 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -570,7 +570,7 @@
 
 	if (pdata && pdata->gpio_base) {
 		ucb->gpio.label = dev_name(&ucb->dev);
-		ucb->gpio.dev = &ucb->dev;
+		ucb->gpio.parent = &ucb->dev;
 		ucb->gpio.owner = THIS_MODULE;
 		ucb->gpio.base = pdata->gpio_base;
 		ucb->gpio.ngpio = 10;
diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c
index 3e628df..855c020 100644
--- a/drivers/mfd/vexpress-sysreg.c
+++ b/drivers/mfd/vexpress-sysreg.c
@@ -11,7 +11,7 @@
  * Copyright (C) 2012 ARM Limited
  */
 
-#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/mfd/core.h>
@@ -164,7 +164,7 @@
 {
 	struct resource *mem;
 	void __iomem *base;
-	struct bgpio_chip *mmc_gpio_chip;
+	struct gpio_chip *mmc_gpio_chip;
 	int master;
 	u32 dt_hbi;
 
@@ -201,8 +201,8 @@
 		return -ENOMEM;
 	bgpio_init(mmc_gpio_chip, &pdev->dev, 0x4, base + SYS_MCI,
 			NULL, NULL, NULL, NULL, 0);
-	mmc_gpio_chip->gc.ngpio = 2;
-	gpiochip_add(&mmc_gpio_chip->gc);
+	mmc_gpio_chip->ngpio = 2;
+	gpiochip_add(mmc_gpio_chip);
 
 	return mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
 			vexpress_sysreg_cells,
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 7e32730..c2dd52e 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3405,7 +3405,9 @@
 	return 0;
 }
 
-#include "../gpu/drm/i915/i915_reg.h"
+#define SOUTH_CHICKEN2		0xc2004
+#define PCH_PP_STATUS		0xc7200
+#define PCH_PP_CONTROL		0xc7204
 #define MSG_CTL			0x45010
 #define NSDE_PWR_STATE		0xd0100
 #define IGD_OPERATION_TIMEOUT	10000     /* set timeout 10 seconds */
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
index 75b0d8c..0f5997c 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -23,7 +23,7 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
@@ -337,14 +337,14 @@
 
 static int bcm2835_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct bcm2835_pinctrl *pc = dev_get_drvdata(chip->dev);
+	struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
 
 	return bcm2835_gpio_get_bit(pc, GPLEV0, offset);
 }
 
 static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct bcm2835_pinctrl *pc = dev_get_drvdata(chip->dev);
+	struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
 
 	bcm2835_gpio_set_bit(pc, value ? GPSET0 : GPCLR0, offset);
 }
@@ -358,7 +358,7 @@
 
 static int bcm2835_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct bcm2835_pinctrl *pc = dev_get_drvdata(chip->dev);
+	struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
 
 	return irq_linear_revmap(pc->irq_domain, offset);
 }
@@ -964,7 +964,7 @@
 		return PTR_ERR(pc->base);
 
 	pc->gpio_chip = bcm2835_gpio_chip;
-	pc->gpio_chip.dev = dev;
+	pc->gpio_chip.parent = dev;
 	pc->gpio_chip.of_node = np;
 
 	pc->irq_domain = irq_domain_add_linear(np, BCM2835_NUM_GPIOS,
@@ -1021,7 +1021,7 @@
 		}
 	}
 
-	err = gpiochip_add(&pc->gpio_chip);
+	err = gpiochip_add_data(&pc->gpio_chip, pc);
 	if (err) {
 		dev_err(dev, "could not add GPIO chip\n");
 		return err;
diff --git a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
index 314591a..3b2ac8f 100644
--- a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
+++ b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
@@ -694,7 +694,7 @@
 	gc->ngpio = ngpios;
 	chip->num_banks = (ngpios + NGPIOS_PER_BANK - 1) / NGPIOS_PER_BANK;
 	gc->label = dev_name(dev);
-	gc->dev = dev;
+	gc->parent = dev;
 	gc->of_node = dev->of_node;
 	gc->request = iproc_gpio_request;
 	gc->free = iproc_gpio_free;
diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
index 725c36f..ac90043 100644
--- a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
+++ b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
@@ -18,7 +18,7 @@
  * through the interaction with the NSP IOMUX controller.
  */
 
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
@@ -81,11 +81,6 @@
 	IO_CTRL
 };
 
-static inline struct nsp_gpio *to_nsp_gpio(struct gpio_chip *gc)
-{
-	return container_of(gc, struct nsp_gpio, gc);
-}
-
 /*
  * Mapping from PINCONF pins to GPIO pins is 1-to-1
  */
@@ -297,7 +292,7 @@
 
 static int nsp_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
 {
-	struct nsp_gpio *chip = to_nsp_gpio(gc);
+	struct nsp_gpio *chip = gpiochip_get_data(gc);
 	unsigned long flags;
 
 	spin_lock_irqsave(&chip->lock, flags);
@@ -311,7 +306,7 @@
 static int nsp_gpio_direction_output(struct gpio_chip *gc, unsigned gpio,
 				     int val)
 {
-	struct nsp_gpio *chip = to_nsp_gpio(gc);
+	struct nsp_gpio *chip = gpiochip_get_data(gc);
 	unsigned long flags;
 
 	spin_lock_irqsave(&chip->lock, flags);
@@ -325,7 +320,7 @@
 
 static void nsp_gpio_set(struct gpio_chip *gc, unsigned gpio, int val)
 {
-	struct nsp_gpio *chip = to_nsp_gpio(gc);
+	struct nsp_gpio *chip = gpiochip_get_data(gc);
 	unsigned long flags;
 
 	spin_lock_irqsave(&chip->lock, flags);
@@ -337,14 +332,14 @@
 
 static int nsp_gpio_get(struct gpio_chip *gc, unsigned gpio)
 {
-	struct nsp_gpio *chip = to_nsp_gpio(gc);
+	struct nsp_gpio *chip = gpiochip_get_data(gc);
 
 	return !!(readl(chip->base + NSP_GPIO_DATA_IN) & BIT(gpio));
 }
 
 static int nsp_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 {
-	struct nsp_gpio *chip = to_nsp_gpio(gc);
+	struct nsp_gpio *chip = gpiochip_get_data(gc);
 
 	return irq_linear_revmap(chip->irq_domain, offset);
 }
@@ -669,7 +664,7 @@
 	gc->can_sleep = false;
 	gc->ngpio = val;
 	gc->label = dev_name(dev);
-	gc->dev = dev;
+	gc->parent = dev;
 	gc->of_node = dev->of_node;
 	gc->request = nsp_gpio_request;
 	gc->free = nsp_gpio_free;
@@ -714,7 +709,7 @@
 		writel(val, (chip->base + NSP_CHIP_A_INT_MASK));
 	}
 
-	ret = gpiochip_add(gc);
+	ret = gpiochip_add_data(gc, chip);
 	if (ret < 0) {
 		dev_err(dev, "unable to add GPIO chip\n");
 		return ret;
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index b59ce75..21b79a4 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -20,7 +20,7 @@
 #include <linux/types.h>
 #include <linux/bitops.h>
 #include <linux/interrupt.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/acpi.h>
 #include <linux/platform_device.h>
 #include <linux/seq_file.h>
@@ -147,12 +147,10 @@
 	struct byt_gpio_pin_context	*saved_context;
 };
 
-#define to_byt_gpio(c)	container_of(c, struct byt_gpio, chip)
-
 static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
 				 int reg)
 {
-	struct byt_gpio *vg = to_byt_gpio(chip);
+	struct byt_gpio *vg = gpiochip_get_data(chip);
 	u32 reg_offset;
 
 	if (reg == BYT_INT_STAT_REG)
@@ -193,7 +191,7 @@
 
 static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
-	struct byt_gpio *vg = to_byt_gpio(chip);
+	struct byt_gpio *vg = gpiochip_get_data(chip);
 	void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG);
 	u32 value, gpio_mux;
 	unsigned long flags;
@@ -229,7 +227,7 @@
 
 static void byt_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
-	struct byt_gpio *vg = to_byt_gpio(chip);
+	struct byt_gpio *vg = gpiochip_get_data(chip);
 
 	byt_gpio_clear_triggering(vg, offset);
 	pm_runtime_put(&vg->pdev->dev);
@@ -237,7 +235,7 @@
 
 static int byt_irq_type(struct irq_data *d, unsigned type)
 {
-	struct byt_gpio *vg = to_byt_gpio(irq_data_get_irq_chip_data(d));
+	struct byt_gpio *vg = gpiochip_get_data(irq_data_get_irq_chip_data(d));
 	u32 offset = irqd_to_hwirq(d);
 	u32 value;
 	unsigned long flags;
@@ -273,7 +271,7 @@
 static int byt_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
 	void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
-	struct byt_gpio *vg = to_byt_gpio(chip);
+	struct byt_gpio *vg = gpiochip_get_data(chip);
 	unsigned long flags;
 	u32 val;
 
@@ -281,12 +279,12 @@
 	val = readl(reg);
 	raw_spin_unlock_irqrestore(&vg->lock, flags);
 
-	return val & BYT_LEVEL;
+	return !!(val & BYT_LEVEL);
 }
 
 static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct byt_gpio *vg = to_byt_gpio(chip);
+	struct byt_gpio *vg = gpiochip_get_data(chip);
 	void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
 	unsigned long flags;
 	u32 old_val;
@@ -305,7 +303,7 @@
 
 static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct byt_gpio *vg = to_byt_gpio(chip);
+	struct byt_gpio *vg = gpiochip_get_data(chip);
 	void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
 	unsigned long flags;
 	u32 value;
@@ -324,7 +322,7 @@
 static int byt_gpio_direction_output(struct gpio_chip *chip,
 				     unsigned gpio, int value)
 {
-	struct byt_gpio *vg = to_byt_gpio(chip);
+	struct byt_gpio *vg = gpiochip_get_data(chip);
 	void __iomem *conf_reg = byt_gpio_reg(chip, gpio, BYT_CONF0_REG);
 	void __iomem *reg = byt_gpio_reg(chip, gpio, BYT_VAL_REG);
 	unsigned long flags;
@@ -356,7 +354,7 @@
 
 static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
-	struct byt_gpio *vg = to_byt_gpio(chip);
+	struct byt_gpio *vg = gpiochip_get_data(chip);
 	int i;
 	u32 conf0, val, offs;
 
@@ -428,7 +426,7 @@
 static void byt_gpio_irq_handler(struct irq_desc *desc)
 {
 	struct irq_data *data = irq_desc_get_irq_data(desc);
-	struct byt_gpio *vg = to_byt_gpio(irq_desc_get_handler_data(desc));
+	struct byt_gpio *vg = gpiochip_get_data(irq_desc_get_handler_data(desc));
 	struct irq_chip *chip = irq_data_get_irq_chip(data);
 	u32 base, pin;
 	void __iomem *reg;
@@ -450,7 +448,7 @@
 static void byt_irq_ack(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct byt_gpio *vg = to_byt_gpio(gc);
+	struct byt_gpio *vg = gpiochip_get_data(gc);
 	unsigned offset = irqd_to_hwirq(d);
 	void __iomem *reg;
 
@@ -463,7 +461,7 @@
 static void byt_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct byt_gpio *vg = to_byt_gpio(gc);
+	struct byt_gpio *vg = gpiochip_get_data(gc);
 	unsigned offset = irqd_to_hwirq(d);
 	unsigned long flags;
 	void __iomem *reg;
@@ -498,7 +496,7 @@
 static void byt_irq_mask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct byt_gpio *vg = to_byt_gpio(gc);
+	struct byt_gpio *vg = gpiochip_get_data(gc);
 
 	byt_gpio_clear_triggering(vg, irqd_to_hwirq(d));
 }
@@ -598,14 +596,14 @@
 	gc->dbg_show = byt_gpio_dbg_show;
 	gc->base = -1;
 	gc->can_sleep = false;
-	gc->dev = dev;
+	gc->parent = dev;
 
 #ifdef CONFIG_PM_SLEEP
 	vg->saved_context = devm_kcalloc(&pdev->dev, gc->ngpio,
 				       sizeof(*vg->saved_context), GFP_KERNEL);
 #endif
 
-	ret = gpiochip_add(gc);
+	ret = gpiochip_add_data(gc, vg);
 	if (ret) {
 		dev_err(&pdev->dev, "failed adding byt-gpio chip\n");
 		return ret;
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
index 84936ba..4251e07 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -181,8 +181,6 @@
 	struct chv_pin_context *saved_pin_context;
 };
 
-#define gpiochip_to_pinctrl(c) container_of(c, struct chv_pinctrl, chip)
-
 #define ALTERNATE_FUNCTION(p, m, i)		\
 	{					\
 		.pin = (p),			\
@@ -1157,7 +1155,7 @@
 
 static int chv_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(chip);
+	struct chv_pinctrl *pctrl = gpiochip_get_data(chip);
 	int pin = chv_gpio_offset_to_pin(pctrl, offset);
 	unsigned long flags;
 	u32 ctrl0, cfg;
@@ -1176,7 +1174,7 @@
 
 static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(chip);
+	struct chv_pinctrl *pctrl = gpiochip_get_data(chip);
 	unsigned pin = chv_gpio_offset_to_pin(pctrl, offset);
 	unsigned long flags;
 	void __iomem *reg;
@@ -1199,7 +1197,7 @@
 
 static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 {
-	struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(chip);
+	struct chv_pinctrl *pctrl = gpiochip_get_data(chip);
 	unsigned pin = chv_gpio_offset_to_pin(pctrl, offset);
 	u32 ctrl0, direction;
 	unsigned long flags;
@@ -1240,7 +1238,7 @@
 static void chv_gpio_irq_ack(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+	struct chv_pinctrl *pctrl = gpiochip_get_data(gc);
 	int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d));
 	u32 intr_line;
 
@@ -1257,7 +1255,7 @@
 static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+	struct chv_pinctrl *pctrl = gpiochip_get_data(gc);
 	int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d));
 	u32 value, intr_line;
 	unsigned long flags;
@@ -1302,7 +1300,7 @@
 	 */
 	if (irqd_get_trigger_type(d) == IRQ_TYPE_NONE) {
 		struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-		struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+		struct chv_pinctrl *pctrl = gpiochip_get_data(gc);
 		unsigned offset = irqd_to_hwirq(d);
 		int pin = chv_gpio_offset_to_pin(pctrl, offset);
 		irq_flow_handler_t handler;
@@ -1334,7 +1332,7 @@
 static int chv_gpio_irq_type(struct irq_data *d, unsigned type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+	struct chv_pinctrl *pctrl = gpiochip_get_data(gc);
 	unsigned offset = irqd_to_hwirq(d);
 	int pin = chv_gpio_offset_to_pin(pctrl, offset);
 	unsigned long flags;
@@ -1407,7 +1405,7 @@
 static void chv_gpio_irq_handler(struct irq_desc *desc)
 {
 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
-	struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+	struct chv_pinctrl *pctrl = gpiochip_get_data(gc);
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	unsigned long pending;
 	u32 intr_line;
@@ -1436,10 +1434,10 @@
 
 	chip->ngpio = pctrl->community->ngpios;
 	chip->label = dev_name(pctrl->dev);
-	chip->dev = pctrl->dev;
+	chip->parent = pctrl->dev;
 	chip->base = -1;
 
-	ret = gpiochip_add(chip);
+	ret = gpiochip_add_data(chip, pctrl);
 	if (ret) {
 		dev_err(pctrl->dev, "Failed to register gpiochip\n");
 		return ret;
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index 26f6b6f..c0f5586 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -103,7 +103,6 @@
 	struct intel_pinctrl_context context;
 };
 
-#define gpiochip_to_pinctrl(c)	container_of(c, struct intel_pinctrl, chip)
 #define pin_to_padno(c, p)	((p) - (c)->pin_base)
 
 static struct intel_community *intel_get_community(struct intel_pinctrl *pctrl,
@@ -596,7 +595,7 @@
 
 static int intel_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct intel_pinctrl *pctrl = gpiochip_to_pinctrl(chip);
+	struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
 	void __iomem *reg;
 
 	reg = intel_get_padcfg(pctrl, offset, PADCFG0);
@@ -608,7 +607,7 @@
 
 static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct intel_pinctrl *pctrl = gpiochip_to_pinctrl(chip);
+	struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
 	void __iomem *reg;
 
 	reg = intel_get_padcfg(pctrl, offset, PADCFG0);
@@ -652,7 +651,7 @@
 static void intel_gpio_irq_ack(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct intel_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+	struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
 	const struct intel_community *community;
 	unsigned pin = irqd_to_hwirq(d);
 
@@ -673,7 +672,7 @@
 static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct intel_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+	struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
 	const struct intel_community *community;
 	unsigned pin = irqd_to_hwirq(d);
 	unsigned long flags;
@@ -713,7 +712,7 @@
 static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct intel_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+	struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
 	unsigned pin = irqd_to_hwirq(d);
 	unsigned long flags;
 	void __iomem *reg;
@@ -767,7 +766,7 @@
 static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct intel_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+	struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
 	const struct intel_community *community;
 	unsigned pin = irqd_to_hwirq(d);
 	unsigned padno, gpp, gpp_offset;
@@ -872,10 +871,10 @@
 
 	pctrl->chip.ngpio = pctrl->soc->npins;
 	pctrl->chip.label = dev_name(pctrl->dev);
-	pctrl->chip.dev = pctrl->dev;
+	pctrl->chip.parent = pctrl->dev;
 	pctrl->chip.base = -1;
 
-	ret = gpiochip_add(&pctrl->chip);
+	ret = gpiochip_add_data(&pctrl->chip, pctrl);
 	if (ret) {
 		dev_err(pctrl->dev, "failed to register gpiochip\n");
 		return ret;
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index e22cbaf..16d48a4 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -14,7 +14,7 @@
  */
 
 #include <linux/io.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
@@ -95,7 +95,7 @@
 {
 	unsigned int reg_addr;
 	unsigned int bit;
-	struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
+	struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
 
 	reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dout_offset;
 	bit = BIT(offset & 0xf);
@@ -750,7 +750,7 @@
 	unsigned int bit;
 	unsigned int read_val = 0;
 
-	struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
+	struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
 
 	reg_addr =  mtk_get_port(pctl, offset) + pctl->devdata->dir_offset;
 	bit = BIT(offset & 0xf);
@@ -763,7 +763,7 @@
 	unsigned int reg_addr;
 	unsigned int bit;
 	unsigned int read_val = 0;
-	struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
+	struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
 
 	reg_addr = mtk_get_port(pctl, offset) +
 		pctl->devdata->din_offset;
@@ -776,7 +776,7 @@
 static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
 	const struct mtk_desc_pin *pin;
-	struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
+	struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
 	int irq;
 
 	pin = pctl->devdata->pins + offset;
@@ -944,7 +944,7 @@
 static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
 	unsigned debounce)
 {
-	struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
+	struct mtk_pinctrl *pctl = dev_get_drvdata(chip->parent);
 	int eint_num, virq, eint_offset;
 	unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask, dbnc;
 	static const unsigned int dbnc_arr[] = {0 , 1, 16, 32, 64, 128, 256};
@@ -1353,10 +1353,10 @@
 	*pctl->chip = mtk_gpio_chip;
 	pctl->chip->ngpio = pctl->devdata->npins;
 	pctl->chip->label = dev_name(&pdev->dev);
-	pctl->chip->dev = &pdev->dev;
+	pctl->chip->parent = &pdev->dev;
 	pctl->chip->base = -1;
 
-	ret = gpiochip_add(pctl->chip);
+	ret = gpiochip_add_data(pctl->chip, pctl);
 	if (ret) {
 		ret = -EINVAL;
 		goto pctrl_error;
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index 84943e4..50cab27 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -448,11 +448,6 @@
 	.is_generic		= true,
 };
 
-static inline struct meson_domain *to_meson_domain(struct gpio_chip *chip)
-{
-	return container_of(chip, struct meson_domain, chip);
-}
-
 static int meson_gpio_request(struct gpio_chip *chip, unsigned gpio)
 {
 	return pinctrl_request_gpio(chip->base + gpio);
@@ -460,14 +455,14 @@
 
 static void meson_gpio_free(struct gpio_chip *chip, unsigned gpio)
 {
-	struct meson_domain *domain = to_meson_domain(chip);
+	struct meson_domain *domain = gpiochip_get_data(chip);
 
 	pinctrl_free_gpio(domain->data->pin_base + gpio);
 }
 
 static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
 {
-	struct meson_domain *domain = to_meson_domain(chip);
+	struct meson_domain *domain = gpiochip_get_data(chip);
 	unsigned int reg, bit, pin;
 	struct meson_bank *bank;
 	int ret;
@@ -485,7 +480,7 @@
 static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
 				       int value)
 {
-	struct meson_domain *domain = to_meson_domain(chip);
+	struct meson_domain *domain = gpiochip_get_data(chip);
 	unsigned int reg, bit, pin;
 	struct meson_bank *bank;
 	int ret;
@@ -507,7 +502,7 @@
 
 static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
 {
-	struct meson_domain *domain = to_meson_domain(chip);
+	struct meson_domain *domain = gpiochip_get_data(chip);
 	unsigned int reg, bit, pin;
 	struct meson_bank *bank;
 	int ret;
@@ -524,7 +519,7 @@
 
 static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio)
 {
-	struct meson_domain *domain = to_meson_domain(chip);
+	struct meson_domain *domain = gpiochip_get_data(chip);
 	unsigned int reg, bit, val, pin;
 	struct meson_bank *bank;
 	int ret;
@@ -562,7 +557,7 @@
 		domain = &pc->domains[i];
 
 		domain->chip.label = domain->data->name;
-		domain->chip.dev = pc->dev;
+		domain->chip.parent = pc->dev;
 		domain->chip.request = meson_gpio_request;
 		domain->chip.free = meson_gpio_free;
 		domain->chip.direction_input = meson_gpio_direction_input;
@@ -575,7 +570,7 @@
 		domain->chip.of_node = domain->of_node;
 		domain->chip.of_gpio_n_cells = 2;
 
-		ret = gpiochip_add(&domain->chip);
+		ret = gpiochip_add_data(&domain->chip, domain);
 		if (ret) {
 			dev_err(pc->dev, "can't add gpio chip %s\n",
 				domain->data->name);
diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c
index b59fbb4..085e601 100644
--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c
+++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c
@@ -109,19 +109,10 @@
 	int irq_cluster_size;
 };
 
-/**
- * to_abx500_pinctrl() - get the pointer to abx500_pinctrl
- * @chip:	Member of the structure abx500_pinctrl
- */
-static inline struct abx500_pinctrl *to_abx500_pinctrl(struct gpio_chip *chip)
-{
-	return container_of(chip, struct abx500_pinctrl, chip);
-}
-
 static int abx500_gpio_get_bit(struct gpio_chip *chip, u8 reg,
 			       unsigned offset, bool *bit)
 {
-	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	struct abx500_pinctrl *pct = gpiochip_get_data(chip);
 	u8 pos = offset % 8;
 	u8 val;
 	int ret;
@@ -143,7 +134,7 @@
 static int abx500_gpio_set_bits(struct gpio_chip *chip, u8 reg,
 				unsigned offset, int val)
 {
-	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	struct abx500_pinctrl *pct = gpiochip_get_data(chip);
 	u8 pos = offset % 8;
 	int ret;
 
@@ -164,7 +155,7 @@
  */
 static int abx500_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	struct abx500_pinctrl *pct = gpiochip_get_data(chip);
 	bool bit;
 	bool is_out;
 	u8 gpio_offset = offset - 1;
@@ -192,7 +183,7 @@
 
 static void abx500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
 {
-	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	struct abx500_pinctrl *pct = gpiochip_get_data(chip);
 	int ret;
 
 	ret = abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
@@ -272,7 +263,7 @@
 
 static bool abx500_pullud_supported(struct gpio_chip *chip, unsigned gpio)
 {
-	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	struct abx500_pinctrl *pct = gpiochip_get_data(chip);
 	struct pullud *pullud = pct->soc->pullud;
 
 	return (pullud &&
@@ -284,7 +275,7 @@
 					unsigned offset,
 					int val)
 {
-	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	struct abx500_pinctrl *pct = gpiochip_get_data(chip);
 	unsigned gpio;
 	int ret;
 
@@ -332,7 +323,7 @@
 
 static int abx500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	struct abx500_pinctrl *pct = gpiochip_get_data(chip);
 	/* The AB8500 GPIO numbers are off by one */
 	int gpio = offset + 1;
 	int hwirq;
@@ -634,7 +625,7 @@
 {
 	unsigned i;
 	unsigned gpio = chip->base;
-	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	struct abx500_pinctrl *pct = gpiochip_get_data(chip);
 	struct pinctrl_dev *pctldev = pct->pctldev;
 
 	for (i = 0; i < chip->ngpio; i++, gpio++) {
@@ -986,7 +977,7 @@
 		param = pinconf_to_config_param(configs[i]);
 		argument = pinconf_to_config_argument(configs[i]);
 
-		dev_dbg(chip->dev, "pin %d [%#lx]: %s %s\n",
+		dev_dbg(chip->parent, "pin %d [%#lx]: %s %s\n",
 			pin, configs[i],
 			(param == PIN_CONFIG_OUTPUT) ? "output " : "input",
 			(param == PIN_CONFIG_OUTPUT) ?
@@ -1077,7 +1068,8 @@
 			break;
 
 		default:
-			dev_err(chip->dev, "illegal configuration requested\n");
+			dev_err(chip->parent,
+				"illegal configuration requested\n");
 		}
 	} /* for each config */
 out:
@@ -1172,7 +1164,7 @@
 	pct->dev = &pdev->dev;
 	pct->parent = dev_get_drvdata(pdev->dev.parent);
 	pct->chip = abx500gpio_chip;
-	pct->chip.dev = &pdev->dev;
+	pct->chip.parent = &pdev->dev;
 	pct->chip.base = -1; /* Dynamic allocation */
 
 	match = of_match_device(abx500_gpio_match, &pdev->dev);
@@ -1210,7 +1202,7 @@
 	pct->irq_cluster = pct->soc->gpio_irq_cluster;
 	pct->irq_cluster_size = pct->soc->ngpio_irq_cluster;
 
-	ret = gpiochip_add(&pct->chip);
+	ret = gpiochip_add_data(&pct->chip, pct);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
 		return ret;
diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
index eebfae0..3524061 100644
--- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c
+++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
@@ -438,7 +438,7 @@
 			       nmk_chip->addr + NMK_GPIO_FIMSC);
 	}
 
-	dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio);
+	dev_dbg(nmk_chip->chip.parent, "%d: clearing interrupt mask\n", gpio);
 }
 
 static void nmk_write_masked(void __iomem *reg, u32 mask, u32 value)
@@ -646,7 +646,7 @@
 static void nmk_gpio_irq_ack(struct irq_data *d)
 {
 	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
-	struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+	struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
 
 	clk_enable(nmk_chip->clk);
 	writel(nmk_gpio_get_bitmask(d->hwirq), nmk_chip->addr + NMK_GPIO_IC);
@@ -863,7 +863,7 @@
 static void nmk_gpio_irq_handler(struct irq_desc *desc)
 {
 	struct gpio_chip *chip = irq_desc_get_handler_data(desc);
-	struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+	struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
 	u32 status;
 
 	clk_enable(nmk_chip->clk);
@@ -876,7 +876,7 @@
 static void nmk_gpio_latent_irq_handler(struct irq_desc *desc)
 {
 	struct gpio_chip *chip = irq_desc_get_handler_data(desc);
-	struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+	struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
 	u32 status = nmk_chip->get_latent_status(nmk_chip->bank);
 
 	__nmk_gpio_irq_handler(desc, status);
@@ -886,8 +886,7 @@
 
 static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct nmk_gpio_chip *nmk_chip =
-		container_of(chip, struct nmk_gpio_chip, chip);
+	struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
 
 	clk_enable(nmk_chip->clk);
 
@@ -900,8 +899,7 @@
 
 static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct nmk_gpio_chip *nmk_chip =
-		container_of(chip, struct nmk_gpio_chip, chip);
+	struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
 	u32 bit = 1 << offset;
 	int value;
 
@@ -917,8 +915,7 @@
 static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
 				int val)
 {
-	struct nmk_gpio_chip *nmk_chip =
-		container_of(chip, struct nmk_gpio_chip, chip);
+	struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
 
 	clk_enable(nmk_chip->clk);
 
@@ -930,8 +927,7 @@
 static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
 				int val)
 {
-	struct nmk_gpio_chip *nmk_chip =
-		container_of(chip, struct nmk_gpio_chip, chip);
+	struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
 
 	clk_enable(nmk_chip->clk);
 
@@ -951,8 +947,7 @@
 	unsigned offset, unsigned gpio)
 {
 	const char *label = gpiochip_is_requested(chip, offset);
-	struct nmk_gpio_chip *nmk_chip =
-		container_of(chip, struct nmk_gpio_chip, chip);
+	struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);
 	int mode;
 	bool is_out;
 	bool data_out;
@@ -1188,7 +1183,7 @@
 	chip->base = id * NMK_GPIO_PER_CHIP;
 	chip->ngpio = NMK_GPIO_PER_CHIP;
 	chip->label = dev_name(&gpio_pdev->dev);
-	chip->dev = &gpio_pdev->dev;
+	chip->parent = &gpio_pdev->dev;
 
 	res = platform_get_resource(gpio_pdev, IORESOURCE_MEM, 0);
 	base = devm_ioremap_resource(&pdev->dev, res);
@@ -1278,7 +1273,7 @@
 	clk_disable(nmk_chip->clk);
 	chip->of_node = np;
 
-	ret = gpiochip_add(chip);
+	ret = gpiochip_add_data(chip, nmk_chip);
 	if (ret)
 		return ret;
 
@@ -1789,7 +1784,7 @@
 		return -EINVAL;
 	}
 	chip = range->gc;
-	nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+	nmk_chip = gpiochip_get_data(chip);
 
 	dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset);
 
@@ -1890,7 +1885,7 @@
 			if (slpm_val)
 				val = slpm_val - 1;
 
-			dev_dbg(nmk_chip->chip.dev,
+			dev_dbg(nmk_chip->chip.parent,
 				"pin %d: sleep pull %s, dir %s, val %s\n",
 				pin,
 				slpm_pull ? pullnames[pull] : "same",
@@ -1899,7 +1894,7 @@
 				slpm_val ? (val ? "high" : "low") : "same");
 		}
 
-		dev_dbg(nmk_chip->chip.dev,
+		dev_dbg(nmk_chip->chip.parent,
 			"pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n",
 			pin, cfg, pullnames[pull], slpmnames[slpm],
 			output ? "output " : "input",
diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c
index 8e9e8ea..ecb57635 100644
--- a/drivers/pinctrl/pinctrl-adi2.c
+++ b/drivers/pinctrl/pinctrl-adi2.c
@@ -636,7 +636,7 @@
 		if (range == NULL) /* should not happen */
 			return -ENODEV;
 
-		port = container_of(range->gc, struct gpio_port, chip);
+		port = gpiochip_get_data(range->gc);
 
 		spin_lock_irqsave(&port->lock, flags);
 
@@ -684,7 +684,7 @@
 	unsigned long flags;
 	u8 offset;
 
-	port = container_of(range->gc, struct gpio_port, chip);
+	port = gpiochip_get_data(range->gc);
 	offset = pin_to_offset(range, pin);
 
 	spin_lock_irqsave(&port->lock, flags);
@@ -718,7 +718,7 @@
 	struct gpio_port *port;
 	unsigned long flags;
 
-	port = container_of(chip, struct gpio_port, chip);
+	port = gpiochip_get_data(chip);
 
 	spin_lock_irqsave(&port->lock, flags);
 
@@ -733,7 +733,7 @@
 static void adi_gpio_set_value(struct gpio_chip *chip, unsigned offset,
 	int value)
 {
-	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
+	struct gpio_port *port = gpiochip_get_data(chip);
 	struct gpio_port_t *regs = port->regs;
 	unsigned long flags;
 
@@ -750,7 +750,7 @@
 static int adi_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 	int value)
 {
-	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
+	struct gpio_port *port = gpiochip_get_data(chip);
 	struct gpio_port_t *regs = port->regs;
 	unsigned long flags;
 
@@ -770,7 +770,7 @@
 
 static int adi_gpio_get_value(struct gpio_chip *chip, unsigned offset)
 {
-	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
+	struct gpio_port *port = gpiochip_get_data(chip);
 	struct gpio_port_t *regs = port->regs;
 	unsigned long flags;
 	int ret;
@@ -786,7 +786,7 @@
 
 static int adi_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
+	struct gpio_port *port = gpiochip_get_data(chip);
 
 	if (port->irq_base >= 0)
 		return irq_find_mapping(port->domain, offset);
@@ -994,7 +994,7 @@
 	port->chip.ngpio		= port->width;
 	gpio = port->chip.base + port->width;
 
-	ret = gpiochip_add(&port->chip);
+	ret = gpiochip_add_data(&port->chip, port);
 	if (ret) {
 		dev_err(&pdev->dev, "Fail to add GPIO chip.\n");
 		goto out_remove_domain;
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index 3318f1d..6574494 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -35,16 +35,11 @@
 #include "pinctrl-utils.h"
 #include "pinctrl-amd.h"
 
-static inline struct amd_gpio *to_amd_gpio(struct gpio_chip *gc)
-{
-	return container_of(gc, struct amd_gpio, gc);
-}
-
 static int amd_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
 {
 	unsigned long flags;
 	u32 pin_reg;
-	struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+	struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 
 	spin_lock_irqsave(&gpio_dev->lock, flags);
 	pin_reg = readl(gpio_dev->base + offset * 4);
@@ -71,7 +66,7 @@
 {
 	u32 pin_reg;
 	unsigned long flags;
-	struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+	struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 
 	spin_lock_irqsave(&gpio_dev->lock, flags);
 	pin_reg = readl(gpio_dev->base + offset * 4);
@@ -90,7 +85,7 @@
 {
 	u32 pin_reg;
 	unsigned long flags;
-	struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+	struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 
 	spin_lock_irqsave(&gpio_dev->lock, flags);
 	pin_reg = readl(gpio_dev->base + offset * 4);
@@ -103,7 +98,7 @@
 {
 	u32 pin_reg;
 	unsigned long flags;
-	struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+	struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 
 	spin_lock_irqsave(&gpio_dev->lock, flags);
 	pin_reg = readl(gpio_dev->base + offset * 4);
@@ -122,7 +117,7 @@
 	u32 pin_reg;
 	int ret = 0;
 	unsigned long flags;
-	struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+	struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 
 	spin_lock_irqsave(&gpio_dev->lock, flags);
 	pin_reg = readl(gpio_dev->base + offset * 4);
@@ -186,7 +181,7 @@
 	u32 pin_reg;
 	unsigned long flags;
 	unsigned int bank, i, pin_num;
-	struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+	struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 
 	char *level_trig;
 	char *active_level;
@@ -327,7 +322,7 @@
 	u32 pin_reg;
 	unsigned long flags;
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+	struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 
 	spin_lock_irqsave(&gpio_dev->lock, flags);
 	pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
@@ -351,7 +346,7 @@
 	u32 pin_reg;
 	unsigned long flags;
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+	struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 
 	spin_lock_irqsave(&gpio_dev->lock, flags);
 	pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
@@ -366,7 +361,7 @@
 	u32 pin_reg;
 	unsigned long flags;
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+	struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 
 	spin_lock_irqsave(&gpio_dev->lock, flags);
 	pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
@@ -380,7 +375,7 @@
 	u32 pin_reg;
 	unsigned long flags;
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+	struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 
 	spin_lock_irqsave(&gpio_dev->lock, flags);
 	pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
@@ -394,7 +389,7 @@
 	u32 reg;
 	unsigned long flags;
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+	struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 
 	spin_lock_irqsave(&gpio_dev->lock, flags);
 	reg = readl(gpio_dev->base + WAKE_INT_MASTER_REG);
@@ -409,7 +404,7 @@
 	u32 pin_reg;
 	unsigned long flags;
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+	struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 
 	spin_lock_irqsave(&gpio_dev->lock, flags);
 	pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
@@ -504,7 +499,7 @@
 	unsigned long flags;
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
-	struct amd_gpio *gpio_dev = to_amd_gpio(gc);
+	struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 
 	chained_irq_enter(chip, desc);
 	/*enable GPIO interrupt again*/
@@ -778,7 +773,7 @@
 	gpio_dev->gc.base			= 0;
 	gpio_dev->gc.label			= pdev->name;
 	gpio_dev->gc.owner			= THIS_MODULE;
-	gpio_dev->gc.dev			= &pdev->dev;
+	gpio_dev->gc.parent			= &pdev->dev;
 	gpio_dev->gc.ngpio			= TOTAL_NUMBER_OF_PINS;
 #if defined(CONFIG_OF_GPIO)
 	gpio_dev->gc.of_node			= pdev->dev.of_node;
@@ -795,7 +790,7 @@
 		return PTR_ERR(gpio_dev->pctrl);
 	}
 
-	ret = gpiochip_add(&gpio_dev->gc);
+	ret = gpiochip_add_data(&gpio_dev->gc, gpio_dev);
 	if (ret)
 		goto out1;
 
diff --git a/drivers/pinctrl/pinctrl-as3722.c b/drivers/pinctrl/pinctrl-as3722.c
index 56af28b..e844fdc 100644
--- a/drivers/pinctrl/pinctrl-as3722.c
+++ b/drivers/pinctrl/pinctrl-as3722.c
@@ -436,14 +436,9 @@
 	.owner = THIS_MODULE,
 };
 
-static inline struct as3722_pctrl_info *to_as_pci(struct gpio_chip *chip)
-{
-	return container_of(chip, struct as3722_pctrl_info, gpio_chip);
-}
-
 static int as3722_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct as3722_pctrl_info *as_pci = to_as_pci(chip);
+	struct as3722_pctrl_info *as_pci = gpiochip_get_data(chip);
 	struct as3722 *as3722 = as_pci->as3722;
 	int ret;
 	u32 reg;
@@ -491,7 +486,7 @@
 static void as3722_gpio_set(struct gpio_chip *chip, unsigned offset,
 		int value)
 {
-	struct as3722_pctrl_info *as_pci = to_as_pci(chip);
+	struct as3722_pctrl_info *as_pci = gpiochip_get_data(chip);
 	struct as3722 *as3722 = as_pci->as3722;
 	int en_invert;
 	u32 val;
@@ -531,7 +526,7 @@
 
 static int as3722_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct as3722_pctrl_info *as_pci = to_as_pci(chip);
+	struct as3722_pctrl_info *as_pci = gpiochip_get_data(chip);
 
 	return as3722_irq_get_virq(as_pci->as3722, offset);
 }
@@ -582,9 +577,9 @@
 	}
 
 	as_pci->gpio_chip = as3722_gpio_chip;
-	as_pci->gpio_chip.dev = &pdev->dev;
+	as_pci->gpio_chip.parent = &pdev->dev;
 	as_pci->gpio_chip.of_node = pdev->dev.parent->of_node;
-	ret = gpiochip_add(&as_pci->gpio_chip);
+	ret = gpiochip_add_data(&as_pci->gpio_chip, as_pci);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Couldn't register gpiochip, %d\n", ret);
 		goto fail_chip_add;
diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c
index d5bdceb..ee69db6 100644
--- a/drivers/pinctrl/pinctrl-at91-pio4.c
+++ b/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -15,6 +15,8 @@
  */
 
 #include <linux/clk.h>
+#include <linux/gpio/driver.h>
+/* FIXME: needed for gpio_to_irq(), get rid of this */
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -290,7 +292,7 @@
 
 static int atmel_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev);
+	struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
 	struct atmel_pin *pin = atmel_pioctrl->pins[offset];
 	unsigned reg;
 
@@ -305,7 +307,7 @@
 
 static int atmel_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev);
+	struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
 	struct atmel_pin *pin = atmel_pioctrl->pins[offset];
 	unsigned reg;
 
@@ -317,7 +319,7 @@
 static int atmel_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 				       int value)
 {
-	struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev);
+	struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
 	struct atmel_pin *pin = atmel_pioctrl->pins[offset];
 	unsigned reg;
 
@@ -336,7 +338,7 @@
 
 static void atmel_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
 {
-	struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev);
+	struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
 	struct atmel_pin *pin = atmel_pioctrl->pins[offset];
 
 	atmel_gpio_write(atmel_pioctrl, pin->bank,
@@ -346,7 +348,7 @@
 
 static int atmel_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev);
+	struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
 
 	return irq_find_mapping(atmel_pioctrl->irq_domain, offset);
 }
@@ -972,7 +974,7 @@
 	atmel_pioctrl->gpio_chip->of_node = dev->of_node;
 	atmel_pioctrl->gpio_chip->ngpio = atmel_pioctrl->npins;
 	atmel_pioctrl->gpio_chip->label = dev_name(dev);
-	atmel_pioctrl->gpio_chip->dev = dev;
+	atmel_pioctrl->gpio_chip->parent = dev;
 	atmel_pioctrl->gpio_chip->names = atmel_pioctrl->group_names;
 
 	atmel_pioctrl->pm_wakeup_sources = devm_kzalloc(dev,
@@ -1040,7 +1042,7 @@
 		goto pinctrl_register_error;
 	}
 
-	ret = gpiochip_add(atmel_pioctrl->gpio_chip);
+	ret = gpiochip_add_data(atmel_pioctrl->gpio_chip, atmel_pioctrl);
 	if (ret) {
 		dev_err(dev, "failed to add gpiochip\n");
 		goto gpiochip_add_error;
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 47b625b..523b6b7 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -45,8 +45,6 @@
 	struct at91_pinctrl_mux_ops *ops;	/* ops */
 };
 
-#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
-
 static struct at91_gpio_chip *gpio_chips[MAX_GPIO_BANKS];
 
 static int gpio_banks;
@@ -811,7 +809,7 @@
 		return -EINVAL;
 	}
 	chip = range->gc;
-	at91_chip = container_of(chip, struct at91_gpio_chip, chip);
+	at91_chip = gpiochip_get_data(chip);
 
 	dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset);
 
@@ -1282,7 +1280,7 @@
 
 static int at91_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 {
-	struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+	struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
 	void __iomem *pio = at91_gpio->regbase;
 	unsigned mask = 1 << offset;
 	u32 osr;
@@ -1293,7 +1291,7 @@
 
 static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+	struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
 	void __iomem *pio = at91_gpio->regbase;
 	unsigned mask = 1 << offset;
 
@@ -1303,7 +1301,7 @@
 
 static int at91_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+	struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
 	void __iomem *pio = at91_gpio->regbase;
 	unsigned mask = 1 << offset;
 	u32 pdsr;
@@ -1315,7 +1313,7 @@
 static void at91_gpio_set(struct gpio_chip *chip, unsigned offset,
 				int val)
 {
-	struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+	struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
 	void __iomem *pio = at91_gpio->regbase;
 	unsigned mask = 1 << offset;
 
@@ -1325,7 +1323,7 @@
 static void at91_gpio_set_multiple(struct gpio_chip *chip,
 				      unsigned long *mask, unsigned long *bits)
 {
-	struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+	struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
 	void __iomem *pio = at91_gpio->regbase;
 
 #define BITS_MASK(bits) (((bits) == 32) ? ~0U : (BIT(bits) - 1))
@@ -1340,7 +1338,7 @@
 static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 				int val)
 {
-	struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+	struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
 	void __iomem *pio = at91_gpio->regbase;
 	unsigned mask = 1 << offset;
 
@@ -1355,7 +1353,7 @@
 {
 	enum at91_mux mode;
 	int i;
-	struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+	struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
 	void __iomem *pio = at91_gpio->regbase;
 
 	for (i = 0; i < chip->ngpio; i++) {
@@ -1570,9 +1568,7 @@
 {
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	struct gpio_chip *gpio_chip = irq_desc_get_handler_data(desc);
-	struct at91_gpio_chip *at91_gpio = container_of(gpio_chip,
-					   struct at91_gpio_chip, chip);
-
+	struct at91_gpio_chip *at91_gpio = gpiochip_get_data(gpio_chip);
 	void __iomem	*pio = at91_gpio->regbase;
 	unsigned long	isr;
 	int		n;
@@ -1648,7 +1644,7 @@
 		return 0;
 	}
 
-	prev = container_of(gpiochip_prev, struct at91_gpio_chip, chip);
+	prev = gpiochip_get_data(gpiochip_prev);
 
 	/* we can only have 2 banks before */
 	for (i = 0; i < 2; i++) {
@@ -1750,7 +1746,7 @@
 	chip = &at91_chip->chip;
 	chip->of_node = np;
 	chip->label = dev_name(&pdev->dev);
-	chip->dev = &pdev->dev;
+	chip->parent = &pdev->dev;
 	chip->owner = THIS_MODULE;
 	chip->base = alias_idx * MAX_NB_GPIO_PER_BANK;
 
@@ -1783,7 +1779,7 @@
 	range->npins = chip->ngpio;
 	range->gc = chip;
 
-	ret = gpiochip_add(chip);
+	ret = gpiochip_add_data(chip, at91_chip);
 	if (ret)
 		goto gpiochip_add_err;
 
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c
index 813eb7c..cf7788d 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -208,25 +208,16 @@
 	}
 };
 
-/**
- * to_u300_gpio() - get the pointer to u300_gpio
- * @chip: the gpio chip member of the structure u300_gpio
- */
-static inline struct u300_gpio *to_u300_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct u300_gpio, chip);
-}
-
 static int u300_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct u300_gpio *gpio = to_u300_gpio(chip);
+	struct u300_gpio *gpio = gpiochip_get_data(chip);
 
-	return readl(U300_PIN_REG(offset, dir)) & U300_PIN_BIT(offset);
+	return !!(readl(U300_PIN_REG(offset, dir)) & U300_PIN_BIT(offset));
 }
 
 static void u300_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct u300_gpio *gpio = to_u300_gpio(chip);
+	struct u300_gpio *gpio = gpiochip_get_data(chip);
 	unsigned long flags;
 	u32 val;
 
@@ -243,7 +234,7 @@
 
 static int u300_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct u300_gpio *gpio = to_u300_gpio(chip);
+	struct u300_gpio *gpio = gpiochip_get_data(chip);
 	unsigned long flags;
 	u32 val;
 
@@ -259,7 +250,7 @@
 static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 				      int value)
 {
-	struct u300_gpio *gpio = to_u300_gpio(chip);
+	struct u300_gpio *gpio = gpiochip_get_data(chip);
 	unsigned long flags;
 	u32 oldmode;
 	u32 val;
@@ -290,7 +281,7 @@
 			 unsigned offset,
 			 unsigned long *config)
 {
-	struct u300_gpio *gpio = to_u300_gpio(chip);
+	struct u300_gpio *gpio = gpiochip_get_data(chip);
 	enum pin_config_param param = (enum pin_config_param) *config;
 	bool biasmode;
 	u32 drmode;
@@ -348,7 +339,7 @@
 int u300_gpio_config_set(struct gpio_chip *chip, unsigned offset,
 			 enum pin_config_param param)
 {
-	struct u300_gpio *gpio = to_u300_gpio(chip);
+	struct u300_gpio *gpio = gpiochip_get_data(chip);
 	unsigned long flags;
 	u32 val;
 
@@ -429,7 +420,7 @@
 static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger)
 {
 	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
-	struct u300_gpio *gpio = to_u300_gpio(chip);
+	struct u300_gpio *gpio = gpiochip_get_data(chip);
 	struct u300_gpio_port *port = &gpio->ports[d->hwirq >> 3];
 	int offset = d->hwirq;
 	u32 val;
@@ -466,7 +457,7 @@
 static void u300_gpio_irq_enable(struct irq_data *d)
 {
 	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
-	struct u300_gpio *gpio = to_u300_gpio(chip);
+	struct u300_gpio *gpio = gpiochip_get_data(chip);
 	struct u300_gpio_port *port = &gpio->ports[d->hwirq >> 3];
 	int offset = d->hwirq;
 	u32 val;
@@ -483,7 +474,7 @@
 static void u300_gpio_irq_disable(struct irq_data *d)
 {
 	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
-	struct u300_gpio *gpio = to_u300_gpio(chip);
+	struct u300_gpio *gpio = gpiochip_get_data(chip);
 	int offset = d->hwirq;
 	u32 val;
 	unsigned long flags;
@@ -506,7 +497,7 @@
 	unsigned int irq = irq_desc_get_irq(desc);
 	struct irq_chip *parent_chip = irq_desc_get_chip(desc);
 	struct gpio_chip *chip = irq_desc_get_handler_data(desc);
-	struct u300_gpio *gpio = to_u300_gpio(chip);
+	struct u300_gpio *gpio = gpiochip_get_data(chip);
 	struct u300_gpio_port *port = &gpio->ports[irq - chip->base];
 	int pinoffset = port->number << 3; /* get the right stride */
 	unsigned long val;
@@ -637,7 +628,7 @@
 
 	gpio->chip = u300_gpio_chip;
 	gpio->chip.ngpio = U300_GPIO_NUM_PORTS * U300_GPIO_PINS_PER_PORT;
-	gpio->chip.dev = &pdev->dev;
+	gpio->chip.parent = &pdev->dev;
 	gpio->chip.base = 0;
 	gpio->dev = &pdev->dev;
 
@@ -684,7 +675,7 @@
 #ifdef CONFIG_OF_GPIO
 	gpio->chip.of_node = pdev->dev.of_node;
 #endif
-	err = gpiochip_add(&gpio->chip);
+	err = gpiochip_add_data(&gpio->chip, gpio);
 	if (err) {
 		dev_err(gpio->dev, "unable to add gpiochip: %d\n", err);
 		goto err_no_chip;
diff --git a/drivers/pinctrl/pinctrl-digicolor.c b/drivers/pinctrl/pinctrl-digicolor.c
index 38a7799..f1343d6 100644
--- a/drivers/pinctrl/pinctrl-digicolor.c
+++ b/drivers/pinctrl/pinctrl-digicolor.c
@@ -171,7 +171,7 @@
 
 static int dc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
 {
-	struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip);
+	struct dc_pinmap *pmap = gpiochip_get_data(chip);
 	int reg_off = GP_DRIVE0(gpio/PINS_PER_COLLECTION);
 	int bit_off = gpio % PINS_PER_COLLECTION;
 	u8 drive;
@@ -191,7 +191,7 @@
 static int dc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
 				    int value)
 {
-	struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip);
+	struct dc_pinmap *pmap = gpiochip_get_data(chip);
 	int reg_off = GP_DRIVE0(gpio/PINS_PER_COLLECTION);
 	int bit_off = gpio % PINS_PER_COLLECTION;
 	u8 drive;
@@ -210,7 +210,7 @@
 
 static int dc_gpio_get(struct gpio_chip *chip, unsigned gpio)
 {
-	struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip);
+	struct dc_pinmap *pmap = gpiochip_get_data(chip);
 	int reg_off = GP_INPUT(gpio/PINS_PER_COLLECTION);
 	int bit_off = gpio % PINS_PER_COLLECTION;
 	u8 input;
@@ -222,7 +222,7 @@
 
 static void dc_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
 {
-	struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip);
+	struct dc_pinmap *pmap = gpiochip_get_data(chip);
 	int reg_off = GP_OUTPUT0(gpio/PINS_PER_COLLECTION);
 	int bit_off = gpio % PINS_PER_COLLECTION;
 	u8 output;
@@ -244,7 +244,7 @@
 	int ret;
 
 	chip->label		= DRIVER_NAME;
-	chip->dev		= pmap->dev;
+	chip->parent		= pmap->dev;
 	chip->request		= gpiochip_generic_request;
 	chip->free		= gpiochip_generic_free;
 	chip->direction_input	= dc_gpio_direction_input;
@@ -258,7 +258,7 @@
 
 	spin_lock_init(&pmap->lock);
 
-	ret = gpiochip_add(chip);
+	ret = gpiochip_add_data(chip, pmap);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/pinctrl/pinctrl-pistachio.c b/drivers/pinctrl/pinctrl-pistachio.c
index 85c9046..856f736 100644
--- a/drivers/pinctrl/pinctrl-pistachio.c
+++ b/drivers/pinctrl/pinctrl-pistachio.c
@@ -842,14 +842,9 @@
 	writel(val, pctl->base + reg);
 }
 
-static inline struct pistachio_gpio_bank *gc_to_bank(struct gpio_chip *gc)
-{
-	return container_of(gc, struct pistachio_gpio_bank, gpio_chip);
-}
-
 static inline struct pistachio_gpio_bank *irqd_to_bank(struct irq_data *d)
 {
-	return gc_to_bank(irq_data_get_irq_chip_data(d));
+	return gpiochip_get_data(irq_data_get_irq_chip_data(d));
 }
 
 static inline u32 gpio_readl(struct pistachio_gpio_bank *bank, u32 reg)
@@ -992,7 +987,7 @@
 
 	range = pinctrl_find_gpio_range_from_pin(pctl->pctldev, pg->pin);
 	if (range)
-		gpio_disable(gc_to_bank(range->gc), pg->pin - range->pin_base);
+		gpio_disable(gpiochip_get_data(range->gc), pg->pin - range->pin_base);
 
 	return 0;
 }
@@ -1173,14 +1168,14 @@
 
 static int pistachio_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 {
-	struct pistachio_gpio_bank *bank = gc_to_bank(chip);
+	struct pistachio_gpio_bank *bank = gpiochip_get_data(chip);
 
 	return !(gpio_readl(bank, GPIO_OUTPUT_EN) & BIT(offset));
 }
 
 static int pistachio_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct pistachio_gpio_bank *bank = gc_to_bank(chip);
+	struct pistachio_gpio_bank *bank = gpiochip_get_data(chip);
 	u32 reg;
 
 	if (gpio_readl(bank, GPIO_OUTPUT_EN) & BIT(offset))
@@ -1194,7 +1189,7 @@
 static void pistachio_gpio_set(struct gpio_chip *chip, unsigned offset,
 			       int value)
 {
-	struct pistachio_gpio_bank *bank = gc_to_bank(chip);
+	struct pistachio_gpio_bank *bank = gpiochip_get_data(chip);
 
 	gpio_mask_writel(bank, GPIO_OUTPUT, offset, !!value);
 }
@@ -1202,7 +1197,7 @@
 static int pistachio_gpio_direction_input(struct gpio_chip *chip,
 					  unsigned offset)
 {
-	struct pistachio_gpio_bank *bank = gc_to_bank(chip);
+	struct pistachio_gpio_bank *bank = gpiochip_get_data(chip);
 
 	gpio_mask_writel(bank, GPIO_OUTPUT_EN, offset, 0);
 	gpio_enable(bank, offset);
@@ -1213,7 +1208,7 @@
 static int pistachio_gpio_direction_output(struct gpio_chip *chip,
 					   unsigned offset, int value)
 {
-	struct pistachio_gpio_bank *bank = gc_to_bank(chip);
+	struct pistachio_gpio_bank *bank = gpiochip_get_data(chip);
 
 	pistachio_gpio_set(chip, offset, value);
 	gpio_mask_writel(bank, GPIO_OUTPUT_EN, offset, 1);
@@ -1303,7 +1298,7 @@
 static void pistachio_gpio_irq_handler(struct irq_desc *desc)
 {
 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
-	struct pistachio_gpio_bank *bank = gc_to_bank(gc);
+	struct pistachio_gpio_bank *bank = gpiochip_get_data(gc);
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	unsigned long pending;
 	unsigned int pin;
@@ -1388,9 +1383,9 @@
 		bank->pctl = pctl;
 		bank->base = pctl->base + GPIO_BANK_BASE(i);
 
-		bank->gpio_chip.dev = pctl->dev;
+		bank->gpio_chip.parent = pctl->dev;
 		bank->gpio_chip.of_node = child;
-		ret = gpiochip_add(&bank->gpio_chip);
+		ret = gpiochip_add_data(&bank->gpio_chip, bank);
 		if (ret < 0) {
 			dev_err(pctl->dev, "Failed to add GPIO chip %u: %d\n",
 				i, ret);
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 9128826..183545a 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -224,11 +224,6 @@
 	.reg_stride = 4,
 };
 
-static inline struct rockchip_pin_bank *gc_to_pin_bank(struct gpio_chip *gc)
-{
-	return container_of(gc, struct rockchip_pin_bank, gpio_chip);
-}
-
 static const inline struct rockchip_pin_group *pinctrl_name_to_group(
 					const struct rockchip_pinctrl *info,
 					const char *name)
@@ -973,7 +968,7 @@
 	unsigned long flags;
 	u32 data;
 
-	bank = gc_to_pin_bank(chip);
+	bank = gpiochip_get_data(chip);
 
 	ret = rockchip_set_mux(bank, pin, RK_FUNC_GPIO);
 	if (ret < 0)
@@ -1413,7 +1408,7 @@
 
 static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
 {
-	struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
+	struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
 	void __iomem *reg = bank->reg_base + GPIO_SWPORT_DR;
 	unsigned long flags;
 	u32 data;
@@ -1437,7 +1432,7 @@
  */
 static int rockchip_gpio_get(struct gpio_chip *gc, unsigned offset)
 {
-	struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
+	struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
 	u32 data;
 
 	clk_enable(bank->clk);
@@ -1476,7 +1471,7 @@
  */
 static int rockchip_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 {
-	struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
+	struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
 	unsigned int virq;
 
 	if (!bank->domain)
@@ -1791,11 +1786,11 @@
 		gc = &bank->gpio_chip;
 		gc->base = bank->pin_base;
 		gc->ngpio = bank->nr_pins;
-		gc->dev = &pdev->dev;
+		gc->parent = &pdev->dev;
 		gc->of_node = bank->of_node;
 		gc->label = bank->name;
 
-		ret = gpiochip_add(gc);
+		ret = gpiochip_add_data(gc, bank);
 		if (ret) {
 			dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n",
 							gc->label, ret);
diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
index b58d3f2..fac844a 100644
--- a/drivers/pinctrl/pinctrl-st.c
+++ b/drivers/pinctrl/pinctrl-st.c
@@ -203,9 +203,6 @@
 #define gpio_range_to_bank(chip) \
 		container_of(chip, struct st_gpio_bank, range)
 
-#define gpio_chip_to_bank(chip) \
-		container_of(chip, struct st_gpio_bank, gpio_chip)
-
 #define pc_to_bank(pc) \
 		container_of(pc, struct st_gpio_bank, pc)
 
@@ -744,14 +741,14 @@
 
 static int st_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
+	struct st_gpio_bank *bank = gpiochip_get_data(chip);
 
 	return !!(readl(bank->base + REG_PIO_PIN) & BIT(offset));
 }
 
 static void st_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
+	struct st_gpio_bank *bank = gpiochip_get_data(chip);
 	__st_gpio_set(bank, offset, value);
 }
 
@@ -765,7 +762,7 @@
 static int st_gpio_direction_output(struct gpio_chip *chip,
 	unsigned offset, int value)
 {
-	struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
+	struct st_gpio_bank *bank = gpiochip_get_data(chip);
 
 	__st_gpio_set(bank, offset, value);
 	pinctrl_gpio_direction_output(chip->base + offset);
@@ -775,7 +772,7 @@
 
 static int st_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 {
-	struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
+	struct st_gpio_bank *bank = gpiochip_get_data(chip);
 	struct st_pio_control pc = bank->pc;
 	unsigned long config;
 	unsigned int direction = 0;
@@ -1325,7 +1322,7 @@
 static void st_gpio_irq_mask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct st_gpio_bank *bank = gpio_chip_to_bank(gc);
+	struct st_gpio_bank *bank = gpiochip_get_data(gc);
 
 	writel(BIT(d->hwirq), bank->base + REG_PIO_CLR_PMASK);
 }
@@ -1333,7 +1330,7 @@
 static void st_gpio_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct st_gpio_bank *bank = gpio_chip_to_bank(gc);
+	struct st_gpio_bank *bank = gpiochip_get_data(gc);
 
 	writel(BIT(d->hwirq), bank->base + REG_PIO_SET_PMASK);
 }
@@ -1341,7 +1338,7 @@
 static int st_gpio_irq_set_type(struct irq_data *d, unsigned type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct st_gpio_bank *bank = gpio_chip_to_bank(gc);
+	struct st_gpio_bank *bank = gpiochip_get_data(gc);
 	unsigned long flags;
 	int comp, pin = d->hwirq;
 	u32 val;
@@ -1455,7 +1452,7 @@
 	/* interrupt dedicated per bank */
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
-	struct st_gpio_bank *bank = gpio_chip_to_bank(gc);
+	struct st_gpio_bank *bank = gpiochip_get_data(gc);
 
 	chained_irq_enter(chip, desc);
 	__gpio_irq_handler(bank);
@@ -1522,7 +1519,7 @@
 	bank->gpio_chip.base = bank_num * ST_GPIO_PINS_PER_BANK;
 	bank->gpio_chip.ngpio = ST_GPIO_PINS_PER_BANK;
 	bank->gpio_chip.of_node = np;
-	bank->gpio_chip.dev = dev;
+	bank->gpio_chip.parent = dev;
 	spin_lock_init(&bank->lock);
 
 	of_property_read_string(np, "st,bank-name", &range->name);
@@ -1532,7 +1529,7 @@
 	range->pin_base = range->base = range->id * ST_GPIO_PINS_PER_BANK;
 	range->npins = bank->gpio_chip.ngpio;
 	range->gc = &bank->gpio_chip;
-	err  = gpiochip_add(&bank->gpio_chip);
+	err  = gpiochip_add_data(&bank->gpio_chip, bank);
 	if (err) {
 		dev_err(dev, "Failed to add gpiochip(%d)!\n", bank_num);
 		return err;
diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c
index 7db7469..412c6b7 100644
--- a/drivers/pinctrl/pinctrl-xway.c
+++ b/drivers/pinctrl/pinctrl-xway.c
@@ -1535,7 +1535,7 @@
 /* ---------  gpio_chip related code --------- */
 static void xway_gpio_set(struct gpio_chip *chip, unsigned int pin, int val)
 {
-	struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+	struct ltq_pinmux_info *info = dev_get_drvdata(chip->parent);
 
 	if (val)
 		gpio_setbit(info->membase[0], GPIO_OUT(pin), PORT_PIN(pin));
@@ -1545,14 +1545,14 @@
 
 static int xway_gpio_get(struct gpio_chip *chip, unsigned int pin)
 {
-	struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+	struct ltq_pinmux_info *info = dev_get_drvdata(chip->parent);
 
-	return gpio_getbit(info->membase[0], GPIO_IN(pin), PORT_PIN(pin));
+	return !!gpio_getbit(info->membase[0], GPIO_IN(pin), PORT_PIN(pin));
 }
 
 static int xway_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
 {
-	struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+	struct ltq_pinmux_info *info = dev_get_drvdata(chip->parent);
 
 	gpio_clearbit(info->membase[0], GPIO_DIR(pin), PORT_PIN(pin));
 
@@ -1561,7 +1561,7 @@
 
 static int xway_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, int val)
 {
-	struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+	struct ltq_pinmux_info *info = dev_get_drvdata(chip->parent);
 
 	if (PORT(pin) == PORT3)
 		gpio_setbit(info->membase[0], GPIO3_OD, PORT_PIN(pin));
@@ -1708,7 +1708,7 @@
 	xway_pctrl_desc.pins = xway_info.pads;
 
 	/* load the gpio chip */
-	xway_chip.dev = &pdev->dev;
+	xway_chip.parent = &pdev->dev;
 	ret = gpiochip_add(&xway_chip);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register gpio chip\n");
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 146264a..8777cf0 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -69,11 +69,6 @@
 	void __iomem *regs;
 };
 
-static inline struct msm_pinctrl *to_msm_pinctrl(struct gpio_chip *gc)
-{
-	return container_of(gc, struct msm_pinctrl, chip);
-}
-
 static int msm_get_groups_count(struct pinctrl_dev *pctldev)
 {
 	struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -381,7 +376,7 @@
 static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
 	const struct msm_pingroup *g;
-	struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip);
+	struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
 	unsigned long flags;
 	u32 val;
 
@@ -401,7 +396,7 @@
 static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
 {
 	const struct msm_pingroup *g;
-	struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip);
+	struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
 	unsigned long flags;
 	u32 val;
 
@@ -428,7 +423,7 @@
 static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
 	const struct msm_pingroup *g;
-	struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip);
+	struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
 	u32 val;
 
 	g = &pctrl->soc->groups[offset];
@@ -440,7 +435,7 @@
 static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
 	const struct msm_pingroup *g;
-	struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip);
+	struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
 	unsigned long flags;
 	u32 val;
 
@@ -468,7 +463,7 @@
 				  unsigned gpio)
 {
 	const struct msm_pingroup *g;
-	struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip);
+	struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
 	unsigned func;
 	int is_out;
 	int drive;
@@ -567,7 +562,7 @@
 static void msm_gpio_irq_mask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct msm_pinctrl *pctrl = to_msm_pinctrl(gc);
+	struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
 	const struct msm_pingroup *g;
 	unsigned long flags;
 	u32 val;
@@ -588,7 +583,7 @@
 static void msm_gpio_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct msm_pinctrl *pctrl = to_msm_pinctrl(gc);
+	struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
 	const struct msm_pingroup *g;
 	unsigned long flags;
 	u32 val;
@@ -613,7 +608,7 @@
 static void msm_gpio_irq_ack(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct msm_pinctrl *pctrl = to_msm_pinctrl(gc);
+	struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
 	const struct msm_pingroup *g;
 	unsigned long flags;
 	u32 val;
@@ -638,7 +633,7 @@
 static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct msm_pinctrl *pctrl = to_msm_pinctrl(gc);
+	struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
 	const struct msm_pingroup *g;
 	unsigned long flags;
 	u32 val;
@@ -732,7 +727,7 @@
 static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct msm_pinctrl *pctrl = to_msm_pinctrl(gc);
+	struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
 	unsigned long flags;
 
 	spin_lock_irqsave(&pctrl->lock, flags);
@@ -757,7 +752,7 @@
 {
 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
 	const struct msm_pingroup *g;
-	struct msm_pinctrl *pctrl = to_msm_pinctrl(gc);
+	struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	int irq_pin;
 	int handled = 0;
@@ -800,11 +795,11 @@
 	chip->base = 0;
 	chip->ngpio = ngpio;
 	chip->label = dev_name(pctrl->dev);
-	chip->dev = pctrl->dev;
+	chip->parent = pctrl->dev;
 	chip->owner = THIS_MODULE;
 	chip->of_node = pctrl->dev->of_node;
 
-	ret = gpiochip_add(&pctrl->chip);
+	ret = gpiochip_add_data(&pctrl->chip, pctrl);
 	if (ret) {
 		dev_err(pctrl->dev, "Failed register gpiochip\n");
 		return ret;
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index 77f6a5c..4e12ded 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -159,11 +159,6 @@
 	PMIC_GPIO_FUNC_DTEST3, PMIC_GPIO_FUNC_DTEST4,
 };
 
-static inline struct pmic_gpio_state *to_gpio_state(struct gpio_chip *chip)
-{
-	return container_of(chip, struct pmic_gpio_state, chip);
-};
-
 static int pmic_gpio_read(struct pmic_gpio_state *state,
 			  struct pmic_gpio_pad *pad, unsigned int addr)
 {
@@ -496,7 +491,7 @@
 
 static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
 {
-	struct pmic_gpio_state *state = to_gpio_state(chip);
+	struct pmic_gpio_state *state = gpiochip_get_data(chip);
 	unsigned long config;
 
 	config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
@@ -507,7 +502,7 @@
 static int pmic_gpio_direction_output(struct gpio_chip *chip,
 				      unsigned pin, int val)
 {
-	struct pmic_gpio_state *state = to_gpio_state(chip);
+	struct pmic_gpio_state *state = gpiochip_get_data(chip);
 	unsigned long config;
 
 	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
@@ -517,7 +512,7 @@
 
 static int pmic_gpio_get(struct gpio_chip *chip, unsigned pin)
 {
-	struct pmic_gpio_state *state = to_gpio_state(chip);
+	struct pmic_gpio_state *state = gpiochip_get_data(chip);
 	struct pmic_gpio_pad *pad;
 	int ret;
 
@@ -534,12 +529,12 @@
 		pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK;
 	}
 
-	return pad->out_value;
+	return !!pad->out_value;
 }
 
 static void pmic_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
 {
-	struct pmic_gpio_state *state = to_gpio_state(chip);
+	struct pmic_gpio_state *state = gpiochip_get_data(chip);
 	unsigned long config;
 
 	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
@@ -562,7 +557,7 @@
 
 static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
 {
-	struct pmic_gpio_state *state = to_gpio_state(chip);
+	struct pmic_gpio_state *state = gpiochip_get_data(chip);
 	struct pmic_gpio_pad *pad;
 
 	pad = state->ctrl->desc->pins[pin].drv_data;
@@ -572,7 +567,7 @@
 
 static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
-	struct pmic_gpio_state *state = to_gpio_state(chip);
+	struct pmic_gpio_state *state = gpiochip_get_data(chip);
 	unsigned i;
 
 	for (i = 0; i < chip->ngpio; i++) {
@@ -762,7 +757,7 @@
 	}
 
 	state->chip = pmic_gpio_gpio_template;
-	state->chip.dev = dev;
+	state->chip.parent = dev;
 	state->chip.base = -1;
 	state->chip.ngpio = npins;
 	state->chip.label = dev_name(dev);
@@ -773,7 +768,7 @@
 	if (IS_ERR(state->ctrl))
 		return PTR_ERR(state->ctrl);
 
-	ret = gpiochip_add(&state->chip);
+	ret = gpiochip_add_data(&state->chip, state);
 	if (ret) {
 		dev_err(state->dev, "can't add gpio chip\n");
 		goto err_chip;
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
index 2df4f29..2f18323 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
@@ -179,11 +179,6 @@
 	"digital", "analog", "sink"
 };
 
-static inline struct pmic_mpp_state *to_mpp_state(struct gpio_chip *chip)
-{
-	return container_of(chip, struct pmic_mpp_state, chip);
-};
-
 static int pmic_mpp_read(struct pmic_mpp_state *state,
 			 struct pmic_mpp_pad *pad, unsigned int addr)
 {
@@ -557,7 +552,7 @@
 
 static int pmic_mpp_direction_input(struct gpio_chip *chip, unsigned pin)
 {
-	struct pmic_mpp_state *state = to_mpp_state(chip);
+	struct pmic_mpp_state *state = gpiochip_get_data(chip);
 	unsigned long config;
 
 	config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
@@ -568,7 +563,7 @@
 static int pmic_mpp_direction_output(struct gpio_chip *chip,
 				     unsigned pin, int val)
 {
-	struct pmic_mpp_state *state = to_mpp_state(chip);
+	struct pmic_mpp_state *state = gpiochip_get_data(chip);
 	unsigned long config;
 
 	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
@@ -578,7 +573,7 @@
 
 static int pmic_mpp_get(struct gpio_chip *chip, unsigned pin)
 {
-	struct pmic_mpp_state *state = to_mpp_state(chip);
+	struct pmic_mpp_state *state = gpiochip_get_data(chip);
 	struct pmic_mpp_pad *pad;
 	int ret;
 
@@ -592,12 +587,12 @@
 		pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK;
 	}
 
-	return pad->out_value;
+	return !!pad->out_value;
 }
 
 static void pmic_mpp_set(struct gpio_chip *chip, unsigned pin, int value)
 {
-	struct pmic_mpp_state *state = to_mpp_state(chip);
+	struct pmic_mpp_state *state = gpiochip_get_data(chip);
 	unsigned long config;
 
 	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
@@ -620,7 +615,7 @@
 
 static int pmic_mpp_to_irq(struct gpio_chip *chip, unsigned pin)
 {
-	struct pmic_mpp_state *state = to_mpp_state(chip);
+	struct pmic_mpp_state *state = gpiochip_get_data(chip);
 	struct pmic_mpp_pad *pad;
 
 	pad = state->ctrl->desc->pins[pin].drv_data;
@@ -630,7 +625,7 @@
 
 static void pmic_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
-	struct pmic_mpp_state *state = to_mpp_state(chip);
+	struct pmic_mpp_state *state = gpiochip_get_data(chip);
 	unsigned i;
 
 	for (i = 0; i < chip->ngpio; i++) {
@@ -865,7 +860,7 @@
 	}
 
 	state->chip = pmic_mpp_gpio_template;
-	state->chip.dev = dev;
+	state->chip.parent = dev;
 	state->chip.base = -1;
 	state->chip.ngpio = npins;
 	state->chip.label = dev_name(dev);
@@ -876,7 +871,7 @@
 	if (IS_ERR(state->ctrl))
 		return PTR_ERR(state->ctrl);
 
-	ret = gpiochip_add(&state->chip);
+	ret = gpiochip_add_data(&state->chip, state);
 	if (ret) {
 		dev_err(state->dev, "can't add gpio chip\n");
 		goto err_chip;
diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
index e51176e..cd8580d 100644
--- a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
@@ -444,7 +444,7 @@
 static int pm8xxx_gpio_direction_input(struct gpio_chip *chip,
 				       unsigned offset)
 {
-	struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip);
+	struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
 	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
 	u8 val;
 
@@ -460,7 +460,7 @@
 					unsigned offset,
 					int value)
 {
-	struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip);
+	struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
 	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
 	u8 val;
 
@@ -478,7 +478,7 @@
 
 static int pm8xxx_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip);
+	struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
 	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
 	bool state;
 	int ret;
@@ -496,7 +496,7 @@
 
 static void pm8xxx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip);
+	struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
 	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
 	u8 val;
 
@@ -525,7 +525,7 @@
 
 static int pm8xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip);
+	struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
 	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
 
 	return pin->irq;
@@ -540,7 +540,7 @@
 				  unsigned offset,
 				  unsigned gpio)
 {
-	struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip);
+	struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
 	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
 
 	static const char * const modes[] = {
@@ -737,12 +737,12 @@
 
 	pctrl->chip = pm8xxx_gpio_template;
 	pctrl->chip.base = -1;
-	pctrl->chip.dev = &pdev->dev;
+	pctrl->chip.parent = &pdev->dev;
 	pctrl->chip.of_node = pdev->dev.of_node;
 	pctrl->chip.of_gpio_n_cells = 2;
 	pctrl->chip.label = dev_name(pctrl->dev);
 	pctrl->chip.ngpio = pctrl->npins;
-	ret = gpiochip_add(&pctrl->chip);
+	ret = gpiochip_add_data(&pctrl->chip, pctrl);
 	if (ret) {
 		dev_err(&pdev->dev, "failed register gpiochip\n");
 		goto unregister_pinctrl;
diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
index e9f01de..54a5402 100644
--- a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
+++ b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
@@ -449,7 +449,7 @@
 static int pm8xxx_mpp_direction_input(struct gpio_chip *chip,
 				       unsigned offset)
 {
-	struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip);
+	struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);
 	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
 
 	switch (pin->mode) {
@@ -473,7 +473,7 @@
 					unsigned offset,
 					int value)
 {
-	struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip);
+	struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);
 	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
 
 	switch (pin->mode) {
@@ -497,13 +497,13 @@
 
 static int pm8xxx_mpp_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip);
+	struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);
 	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
 	bool state;
 	int ret;
 
 	if (!pin->input)
-		return pin->output_value;
+		return !!pin->output_value;
 
 	ret = irq_get_irqchip_state(pin->irq, IRQCHIP_STATE_LINE_LEVEL, &state);
 	if (!ret)
@@ -514,7 +514,7 @@
 
 static void pm8xxx_mpp_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip);
+	struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);
 	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
 
 	pin->output_value = !!value;
@@ -538,7 +538,7 @@
 
 static int pm8xxx_mpp_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip);
+	struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);
 	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
 
 	return pin->irq;
@@ -553,7 +553,7 @@
 				  unsigned offset,
 				  unsigned gpio)
 {
-	struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip);
+	struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);
 	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
 
 	static const char * const aout_lvls[] = {
@@ -828,12 +828,12 @@
 
 	pctrl->chip = pm8xxx_mpp_template;
 	pctrl->chip.base = -1;
-	pctrl->chip.dev = &pdev->dev;
+	pctrl->chip.parent = &pdev->dev;
 	pctrl->chip.of_node = pdev->dev.of_node;
 	pctrl->chip.of_gpio_n_cells = 2;
 	pctrl->chip.label = dev_name(pctrl->dev);
 	pctrl->chip.ngpio = pctrl->npins;
-	ret = gpiochip_add(&pctrl->chip);
+	ret = gpiochip_add_data(&pctrl->chip, pctrl);
 	if (ret) {
 		dev_err(&pdev->dev, "failed register gpiochip\n");
 		goto unregister_pinctrl;
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
index 16e2293..051b5bf 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.c
@@ -176,7 +176,8 @@
 
 	ret = gpiochip_lock_as_irq(&bank->gpio_chip, irqd->hwirq);
 	if (ret) {
-		dev_err(bank->gpio_chip.dev, "unable to lock pin %s-%lu IRQ\n",
+		dev_err(bank->gpio_chip.parent,
+			"unable to lock pin %s-%lu IRQ\n",
 			bank->name, irqd->hwirq);
 		return ret;
 	}
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos5440.c b/drivers/pinctrl/samsung/pinctrl-exynos5440.c
index 82dc109..00ab63a 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos5440.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos5440.c
@@ -15,7 +15,7 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/device.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
@@ -539,7 +539,7 @@
 /* gpiolib gpio_set callback function */
 static void exynos5440_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
 {
-	struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+	struct exynos5440_pinctrl_priv_data *priv = gpiochip_get_data(gc);
 	void __iomem *base = priv->reg_base;
 	u32 data;
 
@@ -553,7 +553,7 @@
 /* gpiolib gpio_get callback function */
 static int exynos5440_gpio_get(struct gpio_chip *gc, unsigned offset)
 {
-	struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+	struct exynos5440_pinctrl_priv_data *priv = gpiochip_get_data(gc);
 	void __iomem *base = priv->reg_base;
 	u32 data;
 
@@ -566,7 +566,7 @@
 /* gpiolib gpio_direction_input callback function */
 static int exynos5440_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
 {
-	struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+	struct exynos5440_pinctrl_priv_data *priv = gpiochip_get_data(gc);
 	void __iomem *base = priv->reg_base;
 	u32 data;
 
@@ -586,7 +586,7 @@
 static int exynos5440_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
 							int value)
 {
-	struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+	struct exynos5440_pinctrl_priv_data *priv = gpiochip_get_data(gc);
 	void __iomem *base = priv->reg_base;
 	u32 data;
 
@@ -607,7 +607,7 @@
 /* gpiolib gpio_to_irq callback function */
 static int exynos5440_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 {
-	struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+	struct exynos5440_pinctrl_priv_data *priv = gpiochip_get_data(gc);
 	unsigned int virq;
 
 	if (offset < 16 || offset > 23)
@@ -817,7 +817,7 @@
 	priv->gc = gc;
 	gc->base = 0;
 	gc->ngpio = EXYNOS5440_MAX_PINS;
-	gc->dev = &pdev->dev;
+	gc->parent = &pdev->dev;
 	gc->set = exynos5440_gpio_set;
 	gc->get = exynos5440_gpio_get;
 	gc->direction_input = exynos5440_gpio_direction_input;
@@ -825,7 +825,7 @@
 	gc->to_irq = exynos5440_gpio_to_irq;
 	gc->label = "gpiolib-exynos5440";
 	gc->owner = THIS_MODULE;
-	ret = gpiochip_add(gc);
+	ret = gpiochip_add_data(gc, priv);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register gpio_chip %s, error "
 					"code: %d\n", gc->label, ret);
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c
index 48294e7..f67b1e9 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.c
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.c
@@ -50,11 +50,6 @@
 
 static unsigned int pin_base;
 
-static inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc)
-{
-	return container_of(gc, struct samsung_pin_bank, gpio_chip);
-}
-
 static int samsung_get_group_count(struct pinctrl_dev *pctldev)
 {
 	struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev);
@@ -522,7 +517,7 @@
 /* gpiolib gpio_set callback function */
 static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
 {
-	struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
+	struct samsung_pin_bank *bank = gpiochip_get_data(gc);
 	const struct samsung_pin_bank_type *type = bank->type;
 	unsigned long flags;
 	void __iomem *reg;
@@ -546,7 +541,7 @@
 {
 	void __iomem *reg;
 	u32 data;
-	struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
+	struct samsung_pin_bank *bank = gpiochip_get_data(gc);
 	const struct samsung_pin_bank_type *type = bank->type;
 
 	reg = bank->drvdata->virt_base + bank->pctl_offset;
@@ -571,7 +566,7 @@
 	u32 data, mask, shift;
 	unsigned long flags;
 
-	bank = gc_to_pin_bank(gc);
+	bank = gpiochip_get_data(gc);
 	type = bank->type;
 	drvdata = bank->drvdata;
 
@@ -619,7 +614,7 @@
  */
 static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 {
-	struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
+	struct samsung_pin_bank *bank = gpiochip_get_data(gc);
 	unsigned int virq;
 
 	if (!bank->irq_domain)
@@ -914,11 +909,11 @@
 		gc = &bank->gpio_chip;
 		gc->base = drvdata->pin_base + bank->pin_base;
 		gc->ngpio = bank->nr_pins;
-		gc->dev = &pdev->dev;
+		gc->parent = &pdev->dev;
 		gc->of_node = bank->of_node;
 		gc->label = bank->name;
 
-		ret = gpiochip_add(gc);
+		ret = gpiochip_add_data(gc, bank);
 		if (ret) {
 			dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n",
 							gc->label, ret);
diff --git a/drivers/pinctrl/sh-pfc/gpio.c b/drivers/pinctrl/sh-pfc/gpio.c
index db3f09a..a6681b8 100644
--- a/drivers/pinctrl/sh-pfc/gpio.c
+++ b/drivers/pinctrl/sh-pfc/gpio.c
@@ -38,14 +38,10 @@
 	struct sh_pfc_gpio_pin		*pins;
 };
 
-static struct sh_pfc_chip *gpio_to_pfc_chip(struct gpio_chip *gc)
-{
-	return container_of(gc, struct sh_pfc_chip, gpio_chip);
-}
-
 static struct sh_pfc *gpio_to_pfc(struct gpio_chip *gc)
 {
-	return gpio_to_pfc_chip(gc)->pfc;
+	struct sh_pfc_chip *chip = gpiochip_get_data(gc);
+	return chip->pfc;
 }
 
 static void gpio_get_data_reg(struct sh_pfc_chip *chip, unsigned int offset,
@@ -178,14 +174,14 @@
 static int gpio_pin_direction_output(struct gpio_chip *gc, unsigned offset,
 				    int value)
 {
-	gpio_pin_set_value(gpio_to_pfc_chip(gc), offset, value);
+	gpio_pin_set_value(gpiochip_get_data(gc), offset, value);
 
 	return pinctrl_gpio_direction_output(offset);
 }
 
 static int gpio_pin_get(struct gpio_chip *gc, unsigned offset)
 {
-	struct sh_pfc_chip *chip = gpio_to_pfc_chip(gc);
+	struct sh_pfc_chip *chip = gpiochip_get_data(gc);
 	struct sh_pfc_gpio_data_reg *reg;
 	unsigned int bit;
 	unsigned int pos;
@@ -199,7 +195,7 @@
 
 static void gpio_pin_set(struct gpio_chip *gc, unsigned offset, int value)
 {
-	gpio_pin_set_value(gpio_to_pfc_chip(gc), offset, value);
+	gpio_pin_set_value(gpiochip_get_data(gc), offset, value);
 }
 
 static int gpio_pin_to_irq(struct gpio_chip *gc, unsigned offset)
@@ -246,7 +242,7 @@
 	gc->to_irq = gpio_pin_to_irq;
 
 	gc->label = pfc->info->name;
-	gc->dev = pfc->dev;
+	gc->parent = pfc->dev;
 	gc->owner = THIS_MODULE;
 	gc->base = 0;
 	gc->ngpio = pfc->nr_gpio_pins;
@@ -322,7 +318,7 @@
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	ret = gpiochip_add(&chip->gpio_chip);
+	ret = gpiochip_add_data(&chip->gpio_chip, chip);
 	if (unlikely(ret < 0))
 		return ERR_PTR(ret);
 
diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c
index 053d98e..beb024c 100644
--- a/drivers/pinctrl/sirf/pinctrl-atlas7.c
+++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c
@@ -358,11 +358,6 @@
 	struct atlas7_gpio_bank banks[0];
 };
 
-static inline struct atlas7_gpio_chip *to_atlas7_gpio(struct gpio_chip *gc)
-{
-	return container_of(gc, struct atlas7_gpio_chip, chip);
-}
-
 /**
  * @dev: a pointer back to containing device
  * @virtbase: the offset to the controller in virtual memory
@@ -5642,7 +5637,7 @@
 static void atlas7_gpio_irq_ack(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc);
+	struct atlas7_gpio_chip *a7gc = gpiochip_get_data(gc);
 	struct atlas7_gpio_bank *bank;
 	void __iomem *ctrl_reg;
 	u32 val, pin_in_bank;
@@ -5680,7 +5675,7 @@
 static void atlas7_gpio_irq_mask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc);
+	struct atlas7_gpio_chip *a7gc = gpiochip_get_data(gc);
 	unsigned long flags;
 
 	spin_lock_irqsave(&a7gc->lock, flags);
@@ -5693,7 +5688,7 @@
 static void atlas7_gpio_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc);
+	struct atlas7_gpio_chip *a7gc = gpiochip_get_data(gc);
 	struct atlas7_gpio_bank *bank;
 	void __iomem *ctrl_reg;
 	u32 val, pin_in_bank;
@@ -5717,7 +5712,7 @@
 				unsigned int type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc);
+	struct atlas7_gpio_chip *a7gc = gpiochip_get_data(gc);
 	struct atlas7_gpio_bank *bank;
 	void __iomem *ctrl_reg;
 	u32 val, pin_in_bank;
@@ -5786,7 +5781,7 @@
 static void atlas7_gpio_handle_irq(struct irq_desc *desc)
 {
 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
-	struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc);
+	struct atlas7_gpio_chip *a7gc = gpiochip_get_data(gc);
 	struct atlas7_gpio_bank *bank = NULL;
 	u32 status, ctrl;
 	int pin_in_bank = 0, idx;
@@ -5854,7 +5849,7 @@
 static int atlas7_gpio_request(struct gpio_chip *chip,
 				unsigned int gpio)
 {
-	struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+	struct atlas7_gpio_chip *a7gc = gpiochip_get_data(chip);
 	int ret;
 	unsigned long flags;
 
@@ -5882,7 +5877,7 @@
 static void atlas7_gpio_free(struct gpio_chip *chip,
 				unsigned int gpio)
 {
-	struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+	struct atlas7_gpio_chip *a7gc = gpiochip_get_data(chip);
 	unsigned long flags;
 
 	spin_lock_irqsave(&a7gc->lock, flags);
@@ -5898,7 +5893,7 @@
 static int atlas7_gpio_direction_input(struct gpio_chip *chip,
 					unsigned int gpio)
 {
-	struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+	struct atlas7_gpio_chip *a7gc = gpiochip_get_data(chip);
 	unsigned long flags;
 
 	spin_lock_irqsave(&a7gc->lock, flags);
@@ -5935,7 +5930,7 @@
 static int atlas7_gpio_direction_output(struct gpio_chip *chip,
 				unsigned int gpio, int value)
 {
-	struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+	struct atlas7_gpio_chip *a7gc = gpiochip_get_data(chip);
 	unsigned long flags;
 
 	spin_lock_irqsave(&a7gc->lock, flags);
@@ -5950,7 +5945,7 @@
 static int atlas7_gpio_get_value(struct gpio_chip *chip,
 					unsigned int gpio)
 {
-	struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+	struct atlas7_gpio_chip *a7gc = gpiochip_get_data(chip);
 	struct atlas7_gpio_bank *bank;
 	u32 val, pin_in_bank;
 	unsigned long flags;
@@ -5970,7 +5965,7 @@
 static void atlas7_gpio_set_value(struct gpio_chip *chip,
 				unsigned int gpio, int value)
 {
-	struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(chip);
+	struct atlas7_gpio_chip *a7gc = gpiochip_get_data(chip);
 	struct atlas7_gpio_bank *bank;
 	void __iomem *ctrl_reg;
 	u32 ctrl, pin_in_bank;
@@ -6054,10 +6049,10 @@
 	chip->label = kstrdup(np->name, GFP_KERNEL);
 	chip->of_node = np;
 	chip->of_gpio_n_cells = 2;
-	chip->dev = &pdev->dev;
+	chip->parent = &pdev->dev;
 
 	/* Add gpio chip to system */
-	ret = gpiochip_add(chip);
+	ret = gpiochip_add_data(chip, a7gc);
 	if (ret) {
 		dev_err(&pdev->dev,
 		"%s: error in probe function with status %d\n",
diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c
index edf40df..762c0c9 100644
--- a/drivers/pinctrl/sirf/pinctrl-sirf.c
+++ b/drivers/pinctrl/sirf/pinctrl-sirf.c
@@ -403,11 +403,6 @@
 }
 arch_initcall(sirfsoc_pinmux_init);
 
-static inline struct sirfsoc_gpio_chip *to_sirfsoc_gpio(struct gpio_chip *gc)
-{
-	return container_of(gc, struct sirfsoc_gpio_chip, chip.gc);
-}
-
 static inline struct sirfsoc_gpio_bank *
 sirfsoc_gpio_to_bank(struct sirfsoc_gpio_chip *sgpio, unsigned int offset)
 {
@@ -422,7 +417,7 @@
 static void sirfsoc_gpio_irq_ack(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(gc);
+	struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(gc);
 	struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, d->hwirq);
 	int idx = sirfsoc_gpio_to_bankoff(d->hwirq);
 	u32 val, offset;
@@ -461,7 +456,7 @@
 static void sirfsoc_gpio_irq_mask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(gc);
+	struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(gc);
 	struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, d->hwirq);
 
 	__sirfsoc_gpio_irq_mask(sgpio, bank, d->hwirq % SIRFSOC_GPIO_BANK_SIZE);
@@ -470,7 +465,7 @@
 static void sirfsoc_gpio_irq_unmask(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(gc);
+	struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(gc);
 	struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, d->hwirq);
 	int idx = sirfsoc_gpio_to_bankoff(d->hwirq);
 	u32 val, offset;
@@ -491,7 +486,7 @@
 static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(gc);
+	struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(gc);
 	struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, d->hwirq);
 	int idx = sirfsoc_gpio_to_bankoff(d->hwirq);
 	u32 val, offset;
@@ -553,7 +548,7 @@
 {
 	unsigned int irq = irq_desc_get_irq(desc);
 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
-	struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(gc);
+	struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(gc);
 	struct sirfsoc_gpio_bank *bank;
 	u32 status, ctrl;
 	int idx = 0;
@@ -611,7 +606,7 @@
 
 static int sirfsoc_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
-	struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(chip);
+	struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(chip);
 	struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, offset);
 	unsigned long flags;
 
@@ -634,7 +629,7 @@
 
 static void sirfsoc_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
-	struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(chip);
+	struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(chip);
 	struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, offset);
 	unsigned long flags;
 
@@ -650,7 +645,7 @@
 
 static int sirfsoc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
 {
-	struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(chip);
+	struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(chip);
 	struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, gpio);
 	int idx = sirfsoc_gpio_to_bankoff(gpio);
 	unsigned long flags;
@@ -693,7 +688,7 @@
 static int sirfsoc_gpio_direction_output(struct gpio_chip *chip,
 	unsigned gpio, int value)
 {
-	struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(chip);
+	struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(chip);
 	struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, gpio);
 	int idx = sirfsoc_gpio_to_bankoff(gpio);
 	u32 offset;
@@ -712,7 +707,7 @@
 
 static int sirfsoc_gpio_get_value(struct gpio_chip *chip, unsigned offset)
 {
-	struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(chip);
+	struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(chip);
 	struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, offset);
 	u32 val;
 	unsigned long flags;
@@ -729,7 +724,7 @@
 static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset,
 	int value)
 {
-	struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(chip);
+	struct sirfsoc_gpio_chip *sgpio = gpiochip_get_data(chip);
 	struct sirfsoc_gpio_bank *bank = sirfsoc_gpio_to_bank(sgpio, offset);
 	u32 ctrl;
 	unsigned long flags;
@@ -815,10 +810,10 @@
 	sgpio->chip.gc.of_node = np;
 	sgpio->chip.gc.of_xlate = sirfsoc_gpio_of_xlate;
 	sgpio->chip.gc.of_gpio_n_cells = 2;
-	sgpio->chip.gc.dev = &pdev->dev;
+	sgpio->chip.gc.parent = &pdev->dev;
 	sgpio->chip.regs = regs;
 
-	err = gpiochip_add(&sgpio->chip.gc);
+	err = gpiochip_add_data(&sgpio->chip.gc, sgpio);
 	if (err) {
 		dev_err(&pdev->dev, "%s: error in probe function with status %d\n",
 			np->full_name, err);
diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c
index 1f0af25..4c9b863 100644
--- a/drivers/pinctrl/spear/pinctrl-plgpio.c
+++ b/drivers/pinctrl/spear/pinctrl-plgpio.c
@@ -107,7 +107,7 @@
 /* gpio framework specific routines */
 static int plgpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+	struct plgpio *plgpio = gpiochip_get_data(chip);
 	unsigned long flags;
 
 	/* get correct offset for "offset" pin */
@@ -127,7 +127,7 @@
 static int plgpio_direction_output(struct gpio_chip *chip, unsigned offset,
 		int value)
 {
-	struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+	struct plgpio *plgpio = gpiochip_get_data(chip);
 	unsigned long flags;
 	unsigned dir_offset = offset, wdata_offset = offset, tmp;
 
@@ -159,7 +159,7 @@
 
 static int plgpio_get_value(struct gpio_chip *chip, unsigned offset)
 {
-	struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+	struct plgpio *plgpio = gpiochip_get_data(chip);
 
 	if (offset >= chip->ngpio)
 		return -EINVAL;
@@ -176,7 +176,7 @@
 
 static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+	struct plgpio *plgpio = gpiochip_get_data(chip);
 
 	if (offset >= chip->ngpio)
 		return;
@@ -196,7 +196,7 @@
 
 static int plgpio_request(struct gpio_chip *chip, unsigned offset)
 {
-	struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+	struct plgpio *plgpio = gpiochip_get_data(chip);
 	int gpio = chip->base + offset;
 	unsigned long flags;
 	int ret = 0;
@@ -248,7 +248,7 @@
 
 static void plgpio_free(struct gpio_chip *chip, unsigned offset)
 {
-	struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+	struct plgpio *plgpio = gpiochip_get_data(chip);
 	int gpio = chip->base + offset;
 	unsigned long flags;
 
@@ -280,7 +280,7 @@
 static void plgpio_irq_disable(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct plgpio *plgpio = container_of(gc, struct plgpio, chip);
+	struct plgpio *plgpio = gpiochip_get_data(gc);
 	int offset = d->hwirq;
 	unsigned long flags;
 
@@ -299,7 +299,7 @@
 static void plgpio_irq_enable(struct irq_data *d)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct plgpio *plgpio = container_of(gc, struct plgpio, chip);
+	struct plgpio *plgpio = gpiochip_get_data(gc);
 	int offset = d->hwirq;
 	unsigned long flags;
 
@@ -318,7 +318,7 @@
 static int plgpio_irq_set_type(struct irq_data *d, unsigned trigger)
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct plgpio *plgpio = container_of(gc, struct plgpio, chip);
+	struct plgpio *plgpio = gpiochip_get_data(gc);
 	int offset = d->hwirq;
 	void __iomem *reg_off;
 	unsigned int supported_type = 0, val;
@@ -359,7 +359,7 @@
 static void plgpio_irq_handler(struct irq_desc *desc)
 {
 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
-	struct plgpio *plgpio = container_of(gc, struct plgpio, chip);
+	struct plgpio *plgpio = gpiochip_get_data(gc);
 	struct irq_chip *irqchip = irq_desc_get_chip(desc);
 	int regs_count, count, pin, offset, i = 0;
 	unsigned long pending;
@@ -561,7 +561,7 @@
 	plgpio->chip.get = plgpio_get_value;
 	plgpio->chip.set = plgpio_set_value;
 	plgpio->chip.label = dev_name(&pdev->dev);
-	plgpio->chip.dev = &pdev->dev;
+	plgpio->chip.parent = &pdev->dev;
 	plgpio->chip.owner = THIS_MODULE;
 	plgpio->chip.of_node = pdev->dev.of_node;
 
@@ -573,7 +573,7 @@
 		}
 	}
 
-	ret = gpiochip_add(&plgpio->chip);
+	ret = gpiochip_add_data(&plgpio->chip, plgpio);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to add gpio chip\n");
 		goto unprepare_clk;
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index dead97d..7a2465f 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -12,7 +12,7 @@
 
 #include <linux/io.h>
 #include <linux/clk.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/irqdomain.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/module.h>
@@ -454,7 +454,7 @@
 
 static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
+	struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
 	u32 reg = sunxi_data_reg(offset);
 	u8 index = sunxi_data_offset(offset);
 	u32 set_mux = pctl->desc->irq_read_needs_mux &&
@@ -469,13 +469,13 @@
 	if (set_mux)
 		sunxi_pmx_set(pctl->pctl_dev, offset, SUN4I_FUNC_IRQ);
 
-	return val;
+	return !!val;
 }
 
 static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
 				unsigned offset, int value)
 {
-	struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
+	struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
 	u32 reg = sunxi_data_reg(offset);
 	u8 index = sunxi_data_offset(offset);
 	unsigned long flags;
@@ -522,7 +522,7 @@
 
 static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
+	struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
 	struct sunxi_desc_function *desc;
 	unsigned pinnum = pctl->desc->pin_base + offset;
 	unsigned irqnum;
@@ -536,7 +536,7 @@
 
 	irqnum = desc->irqbank * IRQ_PER_BANK + desc->irqnum;
 
-	dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
+	dev_dbg(chip->parent, "%s: request IRQ for GPIO %d, return %d\n",
 		chip->label, offset + chip->base, irqnum);
 
 	return irq_find_mapping(pctl->domain, irqnum);
@@ -959,10 +959,10 @@
 	pctl->chip->ngpio = round_up(last_pin, PINS_PER_BANK) -
 			    pctl->desc->pin_base;
 	pctl->chip->label = dev_name(&pdev->dev);
-	pctl->chip->dev = &pdev->dev;
+	pctl->chip->parent = &pdev->dev;
 	pctl->chip->base = pctl->desc->pin_base;
 
-	ret = gpiochip_add(pctl->chip);
+	ret = gpiochip_add_data(pctl->chip, pctl);
 	if (ret)
 		goto pinctrl_error;
 
diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c
index fb22d3f..5c261bf 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wmt.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c
@@ -14,7 +14,7 @@
  */
 
 #include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
@@ -488,7 +488,7 @@
 
 static int wmt_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 {
-	struct wmt_pinctrl_data *data = dev_get_drvdata(chip->dev);
+	struct wmt_pinctrl_data *data = gpiochip_get_data(chip);
 	u32 bank = WMT_BANK_FROM_PIN(offset);
 	u32 bit = WMT_BIT_FROM_PIN(offset);
 	u32 reg_dir = data->banks[bank].reg_dir;
@@ -503,7 +503,7 @@
 
 static int wmt_gpio_get_value(struct gpio_chip *chip, unsigned offset)
 {
-	struct wmt_pinctrl_data *data = dev_get_drvdata(chip->dev);
+	struct wmt_pinctrl_data *data = gpiochip_get_data(chip);
 	u32 bank = WMT_BANK_FROM_PIN(offset);
 	u32 bit = WMT_BIT_FROM_PIN(offset);
 	u32 reg_data_in = data->banks[bank].reg_data_in;
@@ -519,7 +519,7 @@
 static void wmt_gpio_set_value(struct gpio_chip *chip, unsigned offset,
 			       int val)
 {
-	struct wmt_pinctrl_data *data = dev_get_drvdata(chip->dev);
+	struct wmt_pinctrl_data *data = gpiochip_get_data(chip);
 	u32 bank = WMT_BANK_FROM_PIN(offset);
 	u32 bit = WMT_BIT_FROM_PIN(offset);
 	u32 reg_data_out = data->banks[bank].reg_data_out;
@@ -575,7 +575,7 @@
 	wmt_desc.npins = data->npins;
 
 	data->gpio_chip = wmt_gpio_chip;
-	data->gpio_chip.dev = &pdev->dev;
+	data->gpio_chip.parent = &pdev->dev;
 	data->gpio_chip.of_node = pdev->dev.of_node;
 	data->gpio_chip.ngpio = data->nbanks * 32;
 
@@ -589,7 +589,7 @@
 		return PTR_ERR(data->pctl_dev);
 	}
 
-	err = gpiochip_add(&data->gpio_chip);
+	err = gpiochip_add_data(&data->gpio_chip, data);
 	if (err) {
 		dev_err(&pdev->dev, "could not add GPIO chip\n");
 		goto fail_gpio;
diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c
index 709f0af..0e73fd1 100644
--- a/drivers/platform/x86/intel_pmic_gpio.c
+++ b/drivers/platform/x86/intel_pmic_gpio.c
@@ -274,11 +274,11 @@
 	pg->chip.base = pdata->gpio_base;
 	pg->chip.ngpio = NUM_GPIO;
 	pg->chip.can_sleep = 1;
-	pg->chip.dev = dev;
+	pg->chip.parent = dev;
 
 	mutex_init(&pg->buslock);
 
-	pg->chip.dev = dev;
+	pg->chip.parent = dev;
 	retval = gpiochip_add(&pg->chip);
 	if (retval) {
 		pr_err("Can not add pmic gpio chip\n");
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index d451330..3f98165 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1174,7 +1174,7 @@
 #ifdef CONFIG_GPIOLIB
 	/* Setup GPIO cotroller */
 	s->gpio.owner		= THIS_MODULE;
-	s->gpio.dev		= dev;
+	s->gpio.parent		= dev;
 	s->gpio.label		= dev_name(dev);
 	s->gpio.direction_input	= max310x_gpio_direction_input;
 	s->gpio.get		= max310x_gpio_get;
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 5815bcb..13f8d5f 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -1193,7 +1193,7 @@
 	if (devtype->nr_gpio) {
 		/* Setup GPIO cotroller */
 		s->gpio.owner		 = THIS_MODULE;
-		s->gpio.dev		 = dev;
+		s->gpio.parent		 = dev;
 		s->gpio.label		 = dev_name(dev);
 		s->gpio.direction_input	 = sc16is7xx_gpio_direction_input;
 		s->gpio.get		 = sc16is7xx_gpio_get;
diff --git a/drivers/video/fbdev/via/via-gpio.c b/drivers/video/fbdev/via/via-gpio.c
index 6f433b8..1e89c34 100644
--- a/drivers/video/fbdev/via/via-gpio.c
+++ b/drivers/video/fbdev/via/via-gpio.c
@@ -6,7 +6,7 @@
  */
 
 #include <linux/spinlock.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/platform_device.h>
 #include <linux/via-core.h>
 #include <linux/via-gpio.h>
@@ -83,9 +83,7 @@
 static void via_gpio_set(struct gpio_chip *chip, unsigned int nr,
 			 int value)
 {
-	struct viafb_gpio_cfg *cfg = container_of(chip,
-						  struct viafb_gpio_cfg,
-						  gpio_chip);
+	struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip);
 	u8 reg;
 	struct viafb_gpio *gpio;
 	unsigned long flags;
@@ -115,9 +113,7 @@
  */
 static int via_gpio_dir_input(struct gpio_chip *chip, unsigned int nr)
 {
-	struct viafb_gpio_cfg *cfg = container_of(chip,
-						  struct viafb_gpio_cfg,
-						  gpio_chip);
+	struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip);
 	struct viafb_gpio *gpio;
 	unsigned long flags;
 
@@ -131,9 +127,7 @@
 
 static int via_gpio_get(struct gpio_chip *chip, unsigned int nr)
 {
-	struct viafb_gpio_cfg *cfg = container_of(chip,
-						  struct viafb_gpio_cfg,
-						  gpio_chip);
+	struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip);
 	u8 reg;
 	struct viafb_gpio *gpio;
 	unsigned long flags;
@@ -142,7 +136,7 @@
 	gpio = cfg->active_gpios[nr];
 	reg = via_read_reg(VIASR, gpio->vg_port_index);
 	spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
-	return reg & (0x04 << gpio->vg_mask_shift);
+	return !!(reg & (0x04 << gpio->vg_mask_shift));
 }
 
 
@@ -255,7 +249,8 @@
 	 * Get registered.
 	 */
 	viafb_gpio_config.gpio_chip.base = -1;  /* Dynamic */
-	ret = gpiochip_add(&viafb_gpio_config.gpio_chip);
+	ret = gpiochip_add_data(&viafb_gpio_config.gpio_chip,
+				&viafb_gpio_config);
 	if (ret) {
 		printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret);
 		viafb_gpio_config.gpio_chip.ngpio = 0;
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 1c427be..4f0e7be 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -46,6 +46,13 @@
 	  get killed. If you say Y here, the watchdog cannot be stopped once
 	  it has been started.
 
+config WATCHDOG_SYSFS
+	bool "Read different watchdog information through sysfs"
+	default n
+	help
+	  Say Y here if you want to enable watchdog device status read through
+	  sysfs attributes.
+
 #
 # General Watchdog drivers
 #
@@ -135,6 +142,16 @@
 	  This driver can also be built as a module. If so the module
 	  will be called menf21bmc_wdt.
 
+config TANGOX_WATCHDOG
+	tristate "Sigma Designs SMP86xx/SMP87xx watchdog"
+	select WATCHDOG_CORE
+	depends on ARCH_TANGOX || COMPILE_TEST
+	help
+	  Support for the watchdog in Sigma Designs SMP86xx (tango3)
+	  and SMP87xx (tango4) family chips.
+
+	  This driver can be built as a module. The module name is tangox_wdt.
+
 config WM831X_WATCHDOG
 	tristate "WM831x watchdog"
 	depends on MFD_WM831X
@@ -161,6 +178,17 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called of_xilinx_wdt.
 
+config ZIIRAVE_WATCHDOG
+	tristate "Zodiac RAVE Watchdog Timer"
+	depends on I2C
+	select WATCHDOG_CORE
+	help
+	  Watchdog driver for the Zodiac Aerospace RAVE Switch Watchdog
+	  Processor.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ziirave_wdt.
+
 # ALPHA Architecture
 
 # ARM Architecture
@@ -173,6 +201,16 @@
 	  ARM Primecell SP805 Watchdog timer. This will reboot your system when
 	  the timeout is reached.
 
+config ASM9260_WATCHDOG
+	tristate "Alphascale ASM9260 watchdog"
+	depends on MACH_ASM9260
+	depends on OF
+	select WATCHDOG_CORE
+	select RESET_CONTROLLER
+	help
+	  Watchdog timer embedded into Alphascale asm9260 chips. This will reboot your
+	  system when the timeout is reached.
+
 config AT91RM9200_WATCHDOG
 	tristate "AT91RM9200 watchdog"
 	depends on SOC_AT91RM9200 && MFD_SYSCON
@@ -426,6 +464,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called nuc900_wdt.
 
+config TS4800_WATCHDOG
+	tristate "TS-4800 Watchdog"
+	depends on HAS_IOMEM && OF
+	select WATCHDOG_CORE
+	select MFD_SYSCON
+	help
+	  Technologic Systems TS-4800 has watchdog timer implemented in
+	  an external FPGA. Say Y here if you want to support for the
+	  watchdog timer on TS-4800 board.
+
 config TS72XX_WATCHDOG
 	tristate "TS-72XX SBC Watchdog"
 	depends on MACH_TS72XX
@@ -578,6 +626,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called lpc18xx_wdt.
 
+config ATLAS7_WATCHDOG
+	tristate "CSRatlas7 watchdog"
+	depends on ARCH_ATLAS7
+	help
+	  Say Y here to include Watchdog timer support for the watchdog
+	  existing on the CSRatlas7 series platforms.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called atlas7_wdt.
+
 # AVR32 Architecture
 
 config AT32AP700X_WDT
@@ -1345,6 +1403,13 @@
 	help
 	  Hardware driver for the Ralink SoC Watchdog Timer.
 
+config MT7621_WDT
+	tristate "Mediatek SoC watchdog"
+	select WATCHDOG_CORE
+	depends on SOC_MT7620 || SOC_MT7621
+	help
+	  Hardware driver for the Mediatek/Ralink MT7621/8 SoC Watchdog Timer.
+
 # PARISC Architecture
 
 # POWERPC Architecture
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 53d4827..f566753 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -30,6 +30,7 @@
 
 # ARM Architecture
 obj-$(CONFIG_ARM_SP805_WATCHDOG) += sp805_wdt.o
+obj-$(CONFIG_ASM9260_WATCHDOG) += asm9260_wdt.o
 obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
 obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
 obj-$(CONFIG_CADENCE_WATCHDOG) += cadence_wdt.o
@@ -53,6 +54,7 @@
 obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
 obj-$(CONFIG_STMP3XXX_RTC_WATCHDOG) += stmp3xxx_rtc_wdt.o
 obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
+obj-$(CONFIG_TS4800_WATCHDOG) += ts4800_wdt.o
 obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
 obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
 obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
@@ -69,6 +71,7 @@
 obj-$(CONFIG_DIGICOLOR_WATCHDOG) += digicolor_wdt.o
 obj-$(CONFIG_LPC18XX_WATCHDOG) += lpc18xx_wdt.o
 obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o
+obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
@@ -149,6 +152,7 @@
 obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o
 obj-$(CONFIG_RALINK_WDT) += rt2880_wdt.o
 obj-$(CONFIG_IMGPDC_WDT) += imgpdc_wdt.o
+obj-$(CONFIG_MT7621_WDT) += mt7621_wdt.o
 
 # PARISC Architecture
 
@@ -187,8 +191,10 @@
 obj-$(CONFIG_DA9062_WATCHDOG) += da9062_wdt.o
 obj-$(CONFIG_DA9063_WATCHDOG) += da9063_wdt.o
 obj-$(CONFIG_GPIO_WATCHDOG)	+= gpio_wdt.o
+obj-$(CONFIG_TANGOX_WATCHDOG) += tangox_wdt.o
 obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
 obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
 obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o
+obj-$(CONFIG_ZIIRAVE_WATCHDOG) += ziirave_wdt.o
 obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
 obj-$(CONFIG_MENF21BMC_WATCHDOG) += menf21bmc_wdt.o
diff --git a/drivers/watchdog/asm9260_wdt.c b/drivers/watchdog/asm9260_wdt.c
new file mode 100644
index 0000000..c9686b2
--- /dev/null
+++ b/drivers/watchdog/asm9260_wdt.c
@@ -0,0 +1,403 @@
+/*
+ * Watchdog driver for Alphascale ASM9260.
+ *
+ * Copyright (c) 2014 Oleksij Rempel <linux@rempel-privat.de>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/reset.h>
+#include <linux/watchdog.h>
+
+#define CLOCK_FREQ	1000000
+
+/* Watchdog Mode register */
+#define HW_WDMOD			0x00
+/* Wake interrupt. Set by HW, can't be cleared. */
+#define BM_MOD_WDINT			BIT(3)
+/* This bit set if timeout reached. Cleared by SW. */
+#define BM_MOD_WDTOF			BIT(2)
+/* HW Reset on timeout */
+#define BM_MOD_WDRESET			BIT(1)
+/* WD enable */
+#define BM_MOD_WDEN			BIT(0)
+
+/*
+ * Watchdog Timer Constant register
+ * Minimal value is 0xff, the meaning of this value
+ * depends on used clock: T = WDCLK * (0xff + 1) * 4
+ */
+#define HW_WDTC				0x04
+#define BM_WDTC_MAX(freq)		(0x7fffffff / (freq))
+
+/* Watchdog Feed register */
+#define HW_WDFEED			0x08
+
+/* Watchdog Timer Value register */
+#define HW_WDTV				0x0c
+
+#define ASM9260_WDT_DEFAULT_TIMEOUT	30
+
+enum asm9260_wdt_mode {
+	HW_RESET,
+	SW_RESET,
+	DEBUG,
+};
+
+struct asm9260_wdt_priv {
+	struct device		*dev;
+	struct watchdog_device	wdd;
+	struct clk		*clk;
+	struct clk		*clk_ahb;
+	struct reset_control	*rst;
+	struct notifier_block	restart_handler;
+
+	void __iomem		*iobase;
+	int			irq;
+	unsigned long		wdt_freq;
+	enum asm9260_wdt_mode	mode;
+};
+
+static int asm9260_wdt_feed(struct watchdog_device *wdd)
+{
+	struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
+
+	iowrite32(0xaa, priv->iobase + HW_WDFEED);
+	iowrite32(0x55, priv->iobase + HW_WDFEED);
+
+	return 0;
+}
+
+static unsigned int asm9260_wdt_gettimeleft(struct watchdog_device *wdd)
+{
+	struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
+	u32 counter;
+
+	counter = ioread32(priv->iobase + HW_WDTV);
+
+	return DIV_ROUND_CLOSEST(counter, priv->wdt_freq);
+}
+
+static int asm9260_wdt_updatetimeout(struct watchdog_device *wdd)
+{
+	struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
+	u32 counter;
+
+	counter = wdd->timeout * priv->wdt_freq;
+
+	iowrite32(counter, priv->iobase + HW_WDTC);
+
+	return 0;
+}
+
+static int asm9260_wdt_enable(struct watchdog_device *wdd)
+{
+	struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
+	u32 mode = 0;
+
+	if (priv->mode == HW_RESET)
+		mode = BM_MOD_WDRESET;
+
+	iowrite32(BM_MOD_WDEN | mode, priv->iobase + HW_WDMOD);
+
+	asm9260_wdt_updatetimeout(wdd);
+
+	asm9260_wdt_feed(wdd);
+
+	return 0;
+}
+
+static int asm9260_wdt_disable(struct watchdog_device *wdd)
+{
+	struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
+
+	/* The only way to disable WD is to reset it. */
+	reset_control_assert(priv->rst);
+	reset_control_deassert(priv->rst);
+
+	return 0;
+}
+
+static int asm9260_wdt_settimeout(struct watchdog_device *wdd, unsigned int to)
+{
+	wdd->timeout = to;
+	asm9260_wdt_updatetimeout(wdd);
+
+	return 0;
+}
+
+static void asm9260_wdt_sys_reset(struct asm9260_wdt_priv *priv)
+{
+	/* init WD if it was not started */
+
+	iowrite32(BM_MOD_WDEN | BM_MOD_WDRESET, priv->iobase + HW_WDMOD);
+
+	iowrite32(0xff, priv->iobase + HW_WDTC);
+	/* first pass correct sequence */
+	asm9260_wdt_feed(&priv->wdd);
+	/*
+	 * Then write wrong pattern to the feed to trigger reset
+	 * ASAP.
+	 */
+	iowrite32(0xff, priv->iobase + HW_WDFEED);
+
+	mdelay(1000);
+}
+
+static irqreturn_t asm9260_wdt_irq(int irq, void *devid)
+{
+	struct asm9260_wdt_priv *priv = devid;
+	u32 stat;
+
+	stat = ioread32(priv->iobase + HW_WDMOD);
+	if (!(stat & BM_MOD_WDINT))
+		return IRQ_NONE;
+
+	if (priv->mode == DEBUG) {
+		dev_info(priv->dev, "Watchdog Timeout. Do nothing.\n");
+	} else {
+		dev_info(priv->dev, "Watchdog Timeout. Doing SW Reset.\n");
+		asm9260_wdt_sys_reset(priv);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int asm9260_restart_handler(struct notifier_block *this,
+				   unsigned long mode, void *cmd)
+{
+	struct asm9260_wdt_priv *priv =
+		container_of(this, struct asm9260_wdt_priv, restart_handler);
+
+	asm9260_wdt_sys_reset(priv);
+
+	return NOTIFY_DONE;
+}
+
+static const struct watchdog_info asm9260_wdt_ident = {
+	.options          =     WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING
+				| WDIOF_MAGICCLOSE,
+	.identity         =	"Alphascale asm9260 Watchdog",
+};
+
+static struct watchdog_ops asm9260_wdt_ops = {
+	.owner		= THIS_MODULE,
+	.start		= asm9260_wdt_enable,
+	.stop		= asm9260_wdt_disable,
+	.get_timeleft	= asm9260_wdt_gettimeleft,
+	.ping		= asm9260_wdt_feed,
+	.set_timeout	= asm9260_wdt_settimeout,
+};
+
+static int asm9260_wdt_get_dt_clks(struct asm9260_wdt_priv *priv)
+{
+	int err;
+	unsigned long clk;
+
+	priv->clk = devm_clk_get(priv->dev, "mod");
+	if (IS_ERR(priv->clk)) {
+		dev_err(priv->dev, "Failed to get \"mod\" clk\n");
+		return PTR_ERR(priv->clk);
+	}
+
+	/* configure AHB clock */
+	priv->clk_ahb = devm_clk_get(priv->dev, "ahb");
+	if (IS_ERR(priv->clk_ahb)) {
+		dev_err(priv->dev, "Failed to get \"ahb\" clk\n");
+		return PTR_ERR(priv->clk_ahb);
+	}
+
+	err = clk_prepare_enable(priv->clk_ahb);
+	if (err) {
+		dev_err(priv->dev, "Failed to enable ahb_clk!\n");
+		return err;
+	}
+
+	err = clk_set_rate(priv->clk, CLOCK_FREQ);
+	if (err) {
+		clk_disable_unprepare(priv->clk_ahb);
+		dev_err(priv->dev, "Failed to set rate!\n");
+		return err;
+	}
+
+	err = clk_prepare_enable(priv->clk);
+	if (err) {
+		clk_disable_unprepare(priv->clk_ahb);
+		dev_err(priv->dev, "Failed to enable clk!\n");
+		return err;
+	}
+
+	/* wdt has internal divider */
+	clk = clk_get_rate(priv->clk);
+	if (!clk) {
+		clk_disable_unprepare(priv->clk);
+		clk_disable_unprepare(priv->clk_ahb);
+		dev_err(priv->dev, "Failed, clk is 0!\n");
+		return -EINVAL;
+	}
+
+	priv->wdt_freq = clk / 2;
+
+	return 0;
+}
+
+static void asm9260_wdt_get_dt_mode(struct asm9260_wdt_priv *priv)
+{
+	const char *tmp;
+	int ret;
+
+	/* default mode */
+	priv->mode = HW_RESET;
+
+	ret = of_property_read_string(priv->dev->of_node,
+				      "alphascale,mode", &tmp);
+	if (ret < 0)
+		return;
+
+	if (!strcmp(tmp, "hw"))
+		priv->mode = HW_RESET;
+	else if (!strcmp(tmp, "sw"))
+		priv->mode = SW_RESET;
+	else if (!strcmp(tmp, "debug"))
+		priv->mode = DEBUG;
+	else
+		dev_warn(priv->dev, "unknown reset-type: %s. Using default \"hw\" mode.",
+			 tmp);
+}
+
+static int asm9260_wdt_probe(struct platform_device *pdev)
+{
+	struct asm9260_wdt_priv *priv;
+	struct watchdog_device *wdd;
+	struct resource *res;
+	int ret;
+	const char * const mode_name[] = { "hw", "sw", "debug", };
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(struct asm9260_wdt_priv),
+			    GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->iobase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->iobase))
+		return PTR_ERR(priv->iobase);
+
+	ret = asm9260_wdt_get_dt_clks(priv);
+	if (ret)
+		return ret;
+
+	priv->rst = devm_reset_control_get(&pdev->dev, "wdt_rst");
+	if (IS_ERR(priv->rst))
+		return PTR_ERR(priv->rst);
+
+	wdd = &priv->wdd;
+	wdd->info = &asm9260_wdt_ident;
+	wdd->ops = &asm9260_wdt_ops;
+	wdd->min_timeout = 1;
+	wdd->max_timeout = BM_WDTC_MAX(priv->wdt_freq);
+	wdd->parent = &pdev->dev;
+
+	watchdog_set_drvdata(wdd, priv);
+
+	/*
+	 * If 'timeout-sec' unspecified in devicetree, assume a 30 second
+	 * default, unless the max timeout is less than 30 seconds, then use
+	 * the max instead.
+	 */
+	wdd->timeout = ASM9260_WDT_DEFAULT_TIMEOUT;
+	watchdog_init_timeout(wdd, 0, &pdev->dev);
+
+	asm9260_wdt_get_dt_mode(priv);
+
+	if (priv->mode != HW_RESET)
+		priv->irq = platform_get_irq(pdev, 0);
+
+	if (priv->irq > 0) {
+		/*
+		 * Not all supported platforms specify an interrupt for the
+		 * watchdog, so let's make it optional.
+		 */
+		ret = devm_request_irq(&pdev->dev, priv->irq,
+				       asm9260_wdt_irq, 0, pdev->name, priv);
+		if (ret < 0)
+			dev_warn(&pdev->dev, "failed to request IRQ\n");
+	}
+
+	ret = watchdog_register_device(wdd);
+	if (ret)
+		goto clk_off;
+
+	platform_set_drvdata(pdev, priv);
+
+	priv->restart_handler.notifier_call = asm9260_restart_handler;
+	priv->restart_handler.priority = 128;
+	ret = register_restart_handler(&priv->restart_handler);
+	if (ret)
+		dev_warn(&pdev->dev, "cannot register restart handler\n");
+
+	dev_info(&pdev->dev, "Watchdog enabled (timeout: %d sec, mode: %s)\n",
+		 wdd->timeout, mode_name[priv->mode]);
+	return 0;
+
+clk_off:
+	clk_disable_unprepare(priv->clk);
+	clk_disable_unprepare(priv->clk_ahb);
+	return ret;
+}
+
+static void asm9260_wdt_shutdown(struct platform_device *pdev)
+{
+	struct asm9260_wdt_priv *priv = platform_get_drvdata(pdev);
+
+	asm9260_wdt_disable(&priv->wdd);
+}
+
+static int asm9260_wdt_remove(struct platform_device *pdev)
+{
+	struct asm9260_wdt_priv *priv = platform_get_drvdata(pdev);
+
+	asm9260_wdt_disable(&priv->wdd);
+
+	unregister_restart_handler(&priv->restart_handler);
+
+	watchdog_unregister_device(&priv->wdd);
+
+	clk_disable_unprepare(priv->clk);
+	clk_disable_unprepare(priv->clk_ahb);
+
+	return 0;
+}
+
+static const struct of_device_id asm9260_wdt_of_match[] = {
+	{ .compatible = "alphascale,asm9260-wdt"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, asm9260_wdt_of_match);
+
+static struct platform_driver asm9260_wdt_driver = {
+	.driver = {
+		.name = "asm9260-wdt",
+		.owner = THIS_MODULE,
+		.of_match_table	= asm9260_wdt_of_match,
+	},
+	.probe = asm9260_wdt_probe,
+	.remove = asm9260_wdt_remove,
+	.shutdown = asm9260_wdt_shutdown,
+};
+module_platform_driver(asm9260_wdt_driver);
+
+MODULE_DESCRIPTION("asm9260 WatchDog Timer Driver");
+MODULE_AUTHOR("Oleksij Rempel <linux@rempel-privat.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/atlas7_wdt.c b/drivers/watchdog/atlas7_wdt.c
new file mode 100644
index 0000000..df6d924
--- /dev/null
+++ b/drivers/watchdog/atlas7_wdt.c
@@ -0,0 +1,242 @@
+/*
+ * Watchdog driver for CSR Atlas7
+ *
+ * Copyright (c) 2015 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+
+#define ATLAS7_TIMER_WDT_INDEX		5
+#define ATLAS7_WDT_DEFAULT_TIMEOUT	20
+
+#define ATLAS7_WDT_CNT_CTRL	(0 + 4 * ATLAS7_TIMER_WDT_INDEX)
+#define ATLAS7_WDT_CNT_MATCH	(0x18 + 4 * ATLAS7_TIMER_WDT_INDEX)
+#define ATLAS7_WDT_CNT		(0x48 +  4 * ATLAS7_TIMER_WDT_INDEX)
+#define ATLAS7_WDT_CNT_EN	(BIT(0) | BIT(1))
+#define ATLAS7_WDT_EN		0x64
+
+static unsigned int timeout = ATLAS7_WDT_DEFAULT_TIMEOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
+
+module_param(timeout, uint, 0);
+module_param(nowayout, bool, 0);
+
+MODULE_PARM_DESC(timeout, "Default watchdog timeout (in seconds)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+			__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+struct atlas7_wdog {
+	struct device *dev;
+	void __iomem *base;
+	unsigned long tick_rate;
+	struct clk *clk;
+};
+
+static unsigned int atlas7_wdt_gettimeleft(struct watchdog_device *wdd)
+{
+	struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
+	u32 counter, match, delta;
+
+	counter = readl(wdt->base + ATLAS7_WDT_CNT);
+	match = readl(wdt->base + ATLAS7_WDT_CNT_MATCH);
+	delta = match - counter;
+
+	return  delta / wdt->tick_rate;
+}
+
+static int atlas7_wdt_ping(struct watchdog_device *wdd)
+{
+	struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
+	u32 counter, match, delta;
+
+	counter = readl(wdt->base + ATLAS7_WDT_CNT);
+	delta = wdd->timeout * wdt->tick_rate;
+	match = counter + delta;
+
+	writel(match, wdt->base + ATLAS7_WDT_CNT_MATCH);
+
+	return 0;
+}
+
+static int atlas7_wdt_enable(struct watchdog_device *wdd)
+{
+	struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
+
+	atlas7_wdt_ping(wdd);
+
+	writel(readl(wdt->base + ATLAS7_WDT_CNT_CTRL) | ATLAS7_WDT_CNT_EN,
+	      wdt->base + ATLAS7_WDT_CNT_CTRL);
+	writel(1, wdt->base + ATLAS7_WDT_EN);
+
+	return 0;
+}
+
+static int atlas7_wdt_disable(struct watchdog_device *wdd)
+{
+	struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
+
+	writel(0, wdt->base + ATLAS7_WDT_EN);
+	writel(readl(wdt->base + ATLAS7_WDT_CNT_CTRL) & ~ATLAS7_WDT_CNT_EN,
+	      wdt->base + ATLAS7_WDT_CNT_CTRL);
+
+	return 0;
+}
+
+static int atlas7_wdt_settimeout(struct watchdog_device *wdd, unsigned int to)
+{
+	wdd->timeout = to;
+
+	return 0;
+}
+
+#define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)
+
+static const struct watchdog_info atlas7_wdt_ident = {
+	.options = OPTIONS,
+	.firmware_version = 0,
+	.identity = "atlas7 Watchdog",
+};
+
+static struct watchdog_ops atlas7_wdt_ops = {
+	.owner = THIS_MODULE,
+	.start = atlas7_wdt_enable,
+	.stop = atlas7_wdt_disable,
+	.get_timeleft = atlas7_wdt_gettimeleft,
+	.ping = atlas7_wdt_ping,
+	.set_timeout = atlas7_wdt_settimeout,
+};
+
+static struct watchdog_device atlas7_wdd = {
+	.info = &atlas7_wdt_ident,
+	.ops = &atlas7_wdt_ops,
+	.timeout = ATLAS7_WDT_DEFAULT_TIMEOUT,
+};
+
+static const struct of_device_id atlas7_wdt_ids[] = {
+	{ .compatible = "sirf,atlas7-tick"},
+	{}
+};
+
+static int atlas7_wdt_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct atlas7_wdog *wdt;
+	struct resource *res;
+	struct clk *clk;
+	int ret;
+
+	wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+	if (!wdt)
+		return -ENOMEM;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	wdt->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(wdt->base))
+		return PTR_ERR(wdt->base);
+
+	clk = of_clk_get(np, 0);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		dev_err(&pdev->dev, "clk enable failed\n");
+		goto err;
+	}
+
+	/* disable watchdog hardware */
+	writel(0, wdt->base + ATLAS7_WDT_CNT_CTRL);
+
+	wdt->tick_rate = clk_get_rate(clk);
+	wdt->clk = clk;
+	atlas7_wdd.min_timeout = 1;
+	atlas7_wdd.max_timeout = UINT_MAX / wdt->tick_rate;
+
+	watchdog_init_timeout(&atlas7_wdd, 0, &pdev->dev);
+	watchdog_set_nowayout(&atlas7_wdd, nowayout);
+
+	watchdog_set_drvdata(&atlas7_wdd, wdt);
+	platform_set_drvdata(pdev, &atlas7_wdd);
+
+	ret = watchdog_register_device(&atlas7_wdd);
+	if (ret)
+		goto err1;
+
+	return 0;
+
+err1:
+	clk_disable_unprepare(clk);
+err:
+	clk_put(clk);
+	return ret;
+}
+
+static void atlas7_wdt_shutdown(struct platform_device *pdev)
+{
+	struct watchdog_device *wdd = platform_get_drvdata(pdev);
+	struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
+
+	atlas7_wdt_disable(wdd);
+	clk_disable_unprepare(wdt->clk);
+}
+
+static int atlas7_wdt_remove(struct platform_device *pdev)
+{
+	struct watchdog_device *wdd = platform_get_drvdata(pdev);
+	struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
+
+	atlas7_wdt_shutdown(pdev);
+	clk_put(wdt->clk);
+	return 0;
+}
+
+static int __maybe_unused atlas7_wdt_suspend(struct device *dev)
+{
+	/*
+	 * NOTE:timer controller registers settings are saved
+	 * and restored back by the timer-atlas7.c
+	 */
+	return 0;
+}
+
+static int __maybe_unused atlas7_wdt_resume(struct device *dev)
+{
+	struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+	/*
+	 * NOTE: Since timer controller registers settings are saved
+	 * and restored back by the timer-atlas7.c, so we need not
+	 * update WD settings except refreshing timeout.
+	 */
+	atlas7_wdt_ping(wdd);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(atlas7_wdt_pm_ops,
+		atlas7_wdt_suspend, atlas7_wdt_resume);
+
+MODULE_DEVICE_TABLE(of, atlas7_wdt_ids);
+
+static struct platform_driver atlas7_wdt_driver = {
+	.driver = {
+		.name = "atlas7-wdt",
+		.pm = &atlas7_wdt_pm_ops,
+		.of_match_table	= atlas7_wdt_ids,
+	},
+	.probe = atlas7_wdt_probe,
+	.remove = atlas7_wdt_remove,
+	.shutdown = atlas7_wdt_shutdown,
+};
+module_platform_driver(atlas7_wdt_driver);
+
+MODULE_DESCRIPTION("CSRatlas7 watchdog driver");
+MODULE_AUTHOR("Guo Zeng <Guo.Zeng@csr.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:atlas7-wdt");
diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c
index 8a5ce5b..2e6164c 100644
--- a/drivers/watchdog/bcm2835_wdt.c
+++ b/drivers/watchdog/bcm2835_wdt.c
@@ -79,7 +79,6 @@
 	struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog);
 
 	writel_relaxed(PM_PASSWORD | PM_RSTC_RESET, wdt->base + PM_RSTC);
-	dev_info(wdog->dev, "Watchdog timer stopped");
 	return 0;
 }
 
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index 4064a43..df1c2a4 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -20,7 +20,6 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
-#include <linux/reboot.h>
 #include <linux/types.h>
 #include <linux/watchdog.h>
 #include <linux/timer.h>
@@ -88,12 +87,22 @@
 	return 0;
 }
 
+static int bcm47xx_wdt_restart(struct watchdog_device *wdd)
+{
+	struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
+
+	wdt->timer_set(wdt, 1);
+
+	return 0;
+}
+
 static struct watchdog_ops bcm47xx_wdt_hard_ops = {
 	.owner		= THIS_MODULE,
 	.start		= bcm47xx_wdt_hard_start,
 	.stop		= bcm47xx_wdt_hard_stop,
 	.ping		= bcm47xx_wdt_hard_keepalive,
 	.set_timeout	= bcm47xx_wdt_hard_set_timeout,
+	.restart        = bcm47xx_wdt_restart,
 };
 
 static void bcm47xx_wdt_soft_timer_tick(unsigned long data)
@@ -158,34 +167,13 @@
 				WDIOF_MAGICCLOSE,
 };
 
-static int bcm47xx_wdt_notify_sys(struct notifier_block *this,
-				  unsigned long code, void *unused)
-{
-	struct bcm47xx_wdt *wdt;
-
-	wdt = container_of(this, struct bcm47xx_wdt, notifier);
-	if (code == SYS_DOWN || code == SYS_HALT)
-		wdt->wdd.ops->stop(&wdt->wdd);
-	return NOTIFY_DONE;
-}
-
-static int bcm47xx_wdt_restart(struct notifier_block *this, unsigned long mode,
-			       void *cmd)
-{
-	struct bcm47xx_wdt *wdt;
-
-	wdt = container_of(this, struct bcm47xx_wdt, restart_handler);
-	wdt->timer_set(wdt, 1);
-
-	return NOTIFY_DONE;
-}
-
 static struct watchdog_ops bcm47xx_wdt_soft_ops = {
 	.owner		= THIS_MODULE,
 	.start		= bcm47xx_wdt_soft_start,
 	.stop		= bcm47xx_wdt_soft_stop,
 	.ping		= bcm47xx_wdt_soft_keepalive,
 	.set_timeout	= bcm47xx_wdt_soft_set_timeout,
+	.restart        = bcm47xx_wdt_restart,
 };
 
 static int bcm47xx_wdt_probe(struct platform_device *pdev)
@@ -214,32 +202,18 @@
 	if (ret)
 		goto err_timer;
 	watchdog_set_nowayout(&wdt->wdd, nowayout);
-
-	wdt->notifier.notifier_call = &bcm47xx_wdt_notify_sys;
-
-	ret = register_reboot_notifier(&wdt->notifier);
-	if (ret)
-		goto err_timer;
-
-	wdt->restart_handler.notifier_call = &bcm47xx_wdt_restart;
-	wdt->restart_handler.priority = 64;
-	ret = register_restart_handler(&wdt->restart_handler);
-	if (ret)
-		goto err_notifier;
+	watchdog_set_restart_priority(&wdt->wdd, 64);
+	watchdog_stop_on_reboot(&wdt->wdd);
 
 	ret = watchdog_register_device(&wdt->wdd);
 	if (ret)
-		goto err_handler;
+		goto err_timer;
 
 	dev_info(&pdev->dev, "BCM47xx Watchdog Timer enabled (%d seconds%s%s)\n",
 		timeout, nowayout ? ", nowayout" : "",
 		soft ? ", Software Timer" : "");
 	return 0;
 
-err_handler:
-	unregister_restart_handler(&wdt->restart_handler);
-err_notifier:
-	unregister_reboot_notifier(&wdt->notifier);
 err_timer:
 	if (soft)
 		del_timer_sync(&wdt->soft_timer);
@@ -255,7 +229,6 @@
 		return -ENXIO;
 
 	watchdog_unregister_device(&wdt->wdd);
-	unregister_reboot_notifier(&wdt->notifier);
 
 	return 0;
 }
diff --git a/drivers/watchdog/cadence_wdt.c b/drivers/watchdog/cadence_wdt.c
index bcfd2a2..4dda902 100644
--- a/drivers/watchdog/cadence_wdt.c
+++ b/drivers/watchdog/cadence_wdt.c
@@ -18,7 +18,6 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
-#include <linux/reboot.h>
 #include <linux/watchdog.h>
 
 #define CDNS_WDT_DEFAULT_TIMEOUT	10
@@ -72,7 +71,6 @@
  * @ctrl_clksel: counter clock prescaler selection
  * @io_lock: spinlock for IO register access
  * @cdns_wdt_device: watchdog device structure
- * @cdns_wdt_notifier: notifier structure
  *
  * Structure containing parameters specific to cadence watchdog.
  */
@@ -84,7 +82,6 @@
 	u32			ctrl_clksel;
 	spinlock_t		io_lock;
 	struct watchdog_device	cdns_wdt_device;
-	struct notifier_block	cdns_wdt_notifier;
 };
 
 /* Write access to Registers */
@@ -280,29 +277,6 @@
 	.set_timeout = cdns_wdt_settimeout,
 };
 
-/**
- * cdns_wdt_notify_sys - Notifier for reboot or shutdown.
- *
- * @this: handle to notifier block
- * @code: turn off indicator
- * @unused: unused
- * Return: NOTIFY_DONE
- *
- * This notifier is invoked whenever the system reboot or shutdown occur
- * because we need to disable the WDT before system goes down as WDT might
- * reset on the next boot.
- */
-static int cdns_wdt_notify_sys(struct notifier_block *this, unsigned long code,
-			       void *unused)
-{
-	struct cdns_wdt *wdt = container_of(this, struct cdns_wdt,
-					    cdns_wdt_notifier);
-	if (code == SYS_DOWN || code == SYS_HALT)
-		cdns_wdt_stop(&wdt->cdns_wdt_device);
-
-	return NOTIFY_DONE;
-}
-
 /************************Platform Operations*****************************/
 /**
  * cdns_wdt_probe - Probe call for the device.
@@ -360,6 +334,7 @@
 	}
 
 	watchdog_set_nowayout(cdns_wdt_device, nowayout);
+	watchdog_stop_on_reboot(cdns_wdt_device);
 	watchdog_set_drvdata(cdns_wdt_device, wdt);
 
 	wdt->clk = devm_clk_get(&pdev->dev, NULL);
@@ -386,14 +361,6 @@
 
 	spin_lock_init(&wdt->io_lock);
 
-	wdt->cdns_wdt_notifier.notifier_call = &cdns_wdt_notify_sys;
-	ret = register_reboot_notifier(&wdt->cdns_wdt_notifier);
-	if (ret != 0) {
-		dev_err(&pdev->dev, "cannot register reboot notifier err=%d)\n",
-			ret);
-		goto err_clk_disable;
-	}
-
 	ret = watchdog_register_device(cdns_wdt_device);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register wdt device\n");
@@ -427,7 +394,6 @@
 
 	cdns_wdt_stop(&wdt->cdns_wdt_device);
 	watchdog_unregister_device(&wdt->cdns_wdt_device);
-	unregister_reboot_notifier(&wdt->cdns_wdt_notifier);
 	clk_disable_unprepare(wdt->clk);
 
 	return 0;
@@ -455,8 +421,7 @@
  */
 static int __maybe_unused cdns_wdt_suspend(struct device *dev)
 {
-	struct platform_device *pdev = container_of(dev,
-			struct platform_device, dev);
+	struct platform_device *pdev = to_platform_device(dev);
 	struct cdns_wdt *wdt = platform_get_drvdata(pdev);
 
 	cdns_wdt_stop(&wdt->cdns_wdt_device);
@@ -474,8 +439,7 @@
 static int __maybe_unused cdns_wdt_resume(struct device *dev)
 {
 	int ret;
-	struct platform_device *pdev = container_of(dev,
-			struct platform_device, dev);
+	struct platform_device *pdev = to_platform_device(dev);
 	struct cdns_wdt *wdt = platform_get_drvdata(pdev);
 
 	ret = clk_prepare_enable(wdt->clk);
diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c
index 67e6797..2fc19a3 100644
--- a/drivers/watchdog/da9052_wdt.c
+++ b/drivers/watchdog/da9052_wdt.c
@@ -31,7 +31,6 @@
 struct da9052_wdt_data {
 	struct watchdog_device wdt;
 	struct da9052 *da9052;
-	struct kref kref;
 	unsigned long jpast;
 };
 
@@ -51,10 +50,6 @@
 };
 
 
-static void da9052_wdt_release_resources(struct kref *r)
-{
-}
-
 static int da9052_wdt_set_timeout(struct watchdog_device *wdt_dev,
 				  unsigned int timeout)
 {
@@ -104,20 +99,6 @@
 	return 0;
 }
 
-static void da9052_wdt_ref(struct watchdog_device *wdt_dev)
-{
-	struct da9052_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
-
-	kref_get(&driver_data->kref);
-}
-
-static void da9052_wdt_unref(struct watchdog_device *wdt_dev)
-{
-	struct da9052_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
-
-	kref_put(&driver_data->kref, da9052_wdt_release_resources);
-}
-
 static int da9052_wdt_start(struct watchdog_device *wdt_dev)
 {
 	return da9052_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
@@ -170,8 +151,6 @@
 	.stop = da9052_wdt_stop,
 	.ping = da9052_wdt_ping,
 	.set_timeout = da9052_wdt_set_timeout,
-	.ref = da9052_wdt_ref,
-	.unref = da9052_wdt_unref,
 };
 
 
@@ -198,8 +177,6 @@
 	da9052_wdt->parent = &pdev->dev;
 	watchdog_set_drvdata(da9052_wdt, driver_data);
 
-	kref_init(&driver_data->kref);
-
 	ret = da9052_reg_update(da9052, DA9052_CONTROL_D_REG,
 				DA9052_CONTROLD_TWDSCALE, 0);
 	if (ret < 0) {
@@ -225,7 +202,6 @@
 	struct da9052_wdt_data *driver_data = platform_get_drvdata(pdev);
 
 	watchdog_unregister_device(&driver_data->wdt);
-	kref_put(&driver_data->kref, da9052_wdt_release_resources);
 
 	return 0;
 }
diff --git a/drivers/watchdog/da9055_wdt.c b/drivers/watchdog/da9055_wdt.c
index 04d1430..8377c43 100644
--- a/drivers/watchdog/da9055_wdt.c
+++ b/drivers/watchdog/da9055_wdt.c
@@ -35,7 +35,6 @@
 struct da9055_wdt_data {
 	struct watchdog_device wdt;
 	struct da9055 *da9055;
-	struct kref kref;
 };
 
 static const struct {
@@ -99,24 +98,6 @@
 				 DA9055_WATCHDOG_MASK, 1);
 }
 
-static void da9055_wdt_release_resources(struct kref *r)
-{
-}
-
-static void da9055_wdt_ref(struct watchdog_device *wdt_dev)
-{
-	struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
-
-	kref_get(&driver_data->kref);
-}
-
-static void da9055_wdt_unref(struct watchdog_device *wdt_dev)
-{
-	struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
-
-	kref_put(&driver_data->kref, da9055_wdt_release_resources);
-}
-
 static int da9055_wdt_start(struct watchdog_device *wdt_dev)
 {
 	return da9055_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
@@ -138,8 +119,6 @@
 	.stop = da9055_wdt_stop,
 	.ping = da9055_wdt_ping,
 	.set_timeout = da9055_wdt_set_timeout,
-	.ref = da9055_wdt_ref,
-	.unref = da9055_wdt_unref,
 };
 
 static int da9055_wdt_probe(struct platform_device *pdev)
@@ -165,8 +144,6 @@
 	watchdog_set_nowayout(da9055_wdt, nowayout);
 	watchdog_set_drvdata(da9055_wdt, driver_data);
 
-	kref_init(&driver_data->kref);
-
 	ret = da9055_wdt_stop(da9055_wdt);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Failed to stop watchdog, %d\n", ret);
@@ -189,7 +166,6 @@
 	struct da9055_wdt_data *driver_data = platform_get_drvdata(pdev);
 
 	watchdog_unregister_device(&driver_data->wdt);
-	kref_put(&driver_data->kref, da9055_wdt_release_resources);
 
 	return 0;
 }
diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c
index 6bf130b..11e8875 100644
--- a/drivers/watchdog/da9063_wdt.c
+++ b/drivers/watchdog/da9063_wdt.c
@@ -20,7 +20,6 @@
 #include <linux/delay.h>
 #include <linux/mfd/da9063/registers.h>
 #include <linux/mfd/da9063/core.h>
-#include <linux/reboot.h>
 #include <linux/regmap.h>
 
 /*
@@ -39,7 +38,6 @@
 struct da9063_watchdog {
 	struct da9063 *da9063;
 	struct watchdog_device wdtdev;
-	struct notifier_block restart_handler;
 };
 
 static unsigned int da9063_wdt_timeout_to_sel(unsigned int secs)
@@ -121,12 +119,9 @@
 	return ret;
 }
 
-static int da9063_wdt_restart_handler(struct notifier_block *this,
-				      unsigned long mode, void *cmd)
+static int da9063_wdt_restart(struct watchdog_device *wdd)
 {
-	struct da9063_watchdog *wdt = container_of(this,
-						   struct da9063_watchdog,
-						   restart_handler);
+	struct da9063_watchdog *wdt = watchdog_get_drvdata(wdd);
 	int ret;
 
 	ret = regmap_write(wdt->da9063->regmap, DA9063_REG_CONTROL_F,
@@ -135,7 +130,7 @@
 		dev_alert(wdt->da9063->dev, "Failed to shutdown (err = %d)\n",
 			  ret);
 
-	return NOTIFY_DONE;
+	return ret;
 }
 
 static const struct watchdog_info da9063_watchdog_info = {
@@ -149,6 +144,7 @@
 	.stop = da9063_wdt_stop,
 	.ping = da9063_wdt_ping,
 	.set_timeout = da9063_wdt_set_timeout,
+	.restart = da9063_wdt_restart,
 };
 
 static int da9063_wdt_probe(struct platform_device *pdev)
@@ -179,6 +175,8 @@
 
 	wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS;
 
+	watchdog_set_restart_priority(&wdt->wdtdev, 128);
+
 	watchdog_set_drvdata(&wdt->wdtdev, wdt);
 	dev_set_drvdata(&pdev->dev, wdt);
 
@@ -186,13 +184,6 @@
 	if (ret)
 		return ret;
 
-	wdt->restart_handler.notifier_call = da9063_wdt_restart_handler;
-	wdt->restart_handler.priority = 128;
-	ret = register_restart_handler(&wdt->restart_handler);
-	if (ret)
-		dev_err(wdt->da9063->dev,
-			"Failed to register restart handler (err = %d)\n", ret);
-
 	return 0;
 }
 
@@ -200,8 +191,6 @@
 {
 	struct da9063_watchdog *wdt = dev_get_drvdata(&pdev->dev);
 
-	unregister_restart_handler(&wdt->restart_handler);
-
 	watchdog_unregister_device(&wdt->wdtdev);
 
 	return 0;
diff --git a/drivers/watchdog/diag288_wdt.c b/drivers/watchdog/diag288_wdt.c
index 3db9d0e..861d3d3 100644
--- a/drivers/watchdog/diag288_wdt.c
+++ b/drivers/watchdog/diag288_wdt.c
@@ -106,6 +106,10 @@
 	return __diag288(func, timeout, action, 0);
 }
 
+static unsigned long wdt_status;
+
+#define DIAG_WDOG_BUSY	0
+
 static int wdt_start(struct watchdog_device *dev)
 {
 	char *ebc_cmd;
@@ -113,12 +117,17 @@
 	int ret;
 	unsigned int func;
 
+	if (test_and_set_bit(DIAG_WDOG_BUSY, &wdt_status))
+		return -EBUSY;
+
 	ret = -ENODEV;
 
 	if (MACHINE_IS_VM) {
 		ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL);
-		if (!ebc_cmd)
+		if (!ebc_cmd) {
+			clear_bit(DIAG_WDOG_BUSY, &wdt_status);
 			return -ENOMEM;
+		}
 		len = strlcpy(ebc_cmd, wdt_cmd, MAX_CMDLEN);
 		ASCEBC(ebc_cmd, MAX_CMDLEN);
 		EBC_TOUPPER(ebc_cmd, MAX_CMDLEN);
@@ -135,6 +144,7 @@
 
 	if (ret) {
 		pr_err("The watchdog cannot be activated\n");
+		clear_bit(DIAG_WDOG_BUSY, &wdt_status);
 		return ret;
 	}
 	return 0;
@@ -146,6 +156,9 @@
 
 	diag_stat_inc(DIAG_STAT_X288);
 	ret = __diag288(WDT_FUNC_CANCEL, 0, 0, 0);
+
+	clear_bit(DIAG_WDOG_BUSY, &wdt_status);
+
 	return ret;
 }
 
@@ -220,17 +233,10 @@
  * It makes no sense to go into suspend while the watchdog is running.
  * Depending on the memory size, the watchdog might trigger, while we
  * are still saving the memory.
- * We reuse the open flag to ensure that suspend and watchdog open are
- * exclusive operations
  */
 static int wdt_suspend(void)
 {
-	if (test_and_set_bit(WDOG_DEV_OPEN, &wdt_dev.status)) {
-		pr_err("Linux cannot be suspended while the watchdog is in use\n");
-		return notifier_from_errno(-EBUSY);
-	}
-	if (test_bit(WDOG_ACTIVE, &wdt_dev.status)) {
-		clear_bit(WDOG_DEV_OPEN, &wdt_dev.status);
+	if (test_and_set_bit(DIAG_WDOG_BUSY, &wdt_status)) {
 		pr_err("Linux cannot be suspended while the watchdog is in use\n");
 		return notifier_from_errno(-EBUSY);
 	}
@@ -239,7 +245,7 @@
 
 static int wdt_resume(void)
 {
-	clear_bit(WDOG_DEV_OPEN, &wdt_dev.status);
+	clear_bit(DIAG_WDOG_BUSY, &wdt_status);
 	return NOTIFY_DONE;
 }
 
diff --git a/drivers/watchdog/digicolor_wdt.c b/drivers/watchdog/digicolor_wdt.c
index 50abe1b..1ccb0b2 100644
--- a/drivers/watchdog/digicolor_wdt.c
+++ b/drivers/watchdog/digicolor_wdt.c
@@ -15,7 +15,6 @@
 #include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/watchdog.h>
-#include <linux/reboot.h>
 #include <linux/platform_device.h>
 #include <linux/of_address.h>
 
@@ -28,7 +27,6 @@
 struct dc_wdt {
 	void __iomem		*base;
 	struct clk		*clk;
-	struct notifier_block	restart_handler;
 	spinlock_t		lock;
 };
 
@@ -50,16 +48,15 @@
 	spin_unlock_irqrestore(&wdt->lock, flags);
 }
 
-static int dc_restart_handler(struct notifier_block *this, unsigned long mode,
-			      void *cmd)
+static int dc_wdt_restart(struct watchdog_device *wdog)
 {
-	struct dc_wdt *wdt = container_of(this, struct dc_wdt, restart_handler);
+	struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
 
 	dc_wdt_set(wdt, 1);
 	/* wait for reset to assert... */
 	mdelay(500);
 
-	return NOTIFY_DONE;
+	return 0;
 }
 
 static int dc_wdt_start(struct watchdog_device *wdog)
@@ -104,6 +101,7 @@
 	.stop		= dc_wdt_stop,
 	.set_timeout	= dc_wdt_set_timeout,
 	.get_timeleft	= dc_wdt_get_timeleft,
+	.restart        = dc_wdt_restart,
 };
 
 static struct watchdog_info dc_wdt_info = {
@@ -148,6 +146,7 @@
 	spin_lock_init(&wdt->lock);
 
 	watchdog_set_drvdata(&dc_wdt_wdd, wdt);
+	watchdog_set_restart_priority(&dc_wdt_wdd, 128);
 	watchdog_init_timeout(&dc_wdt_wdd, timeout, dev);
 	ret = watchdog_register_device(&dc_wdt_wdd);
 	if (ret) {
@@ -155,12 +154,6 @@
 		goto err_iounmap;
 	}
 
-	wdt->restart_handler.notifier_call = dc_restart_handler;
-	wdt->restart_handler.priority = 128;
-	ret = register_restart_handler(&wdt->restart_handler);
-	if (ret)
-		dev_warn(&pdev->dev, "cannot register restart handler\n");
-
 	return 0;
 
 err_iounmap:
@@ -172,7 +165,6 @@
 {
 	struct dc_wdt *wdt = platform_get_drvdata(pdev);
 
-	unregister_restart_handler(&wdt->restart_handler);
 	watchdog_unregister_device(&dc_wdt_wdd);
 	iounmap(wdt->base);
 
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index 6ea0634..8fefa4ad 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -81,7 +81,7 @@
 	 * There are 16 possible timeout values in 0..15 where the number of
 	 * cycles is 2 ^ (16 + i) and the watchdog counts down.
 	 */
-	return (1 << (16 + top)) / clk_get_rate(dw_wdt.clk);
+	return (1U << (16 + top)) / clk_get_rate(dw_wdt.clk);
 }
 
 static int dw_wdt_get_top(void)
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c
index 90d59d3..ba066e4 100644
--- a/drivers/watchdog/gpio_wdt.c
+++ b/drivers/watchdog/gpio_wdt.c
@@ -12,10 +12,8 @@
 #include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/module.h>
-#include <linux/notifier.h>
 #include <linux/of_gpio.h>
 #include <linux/platform_device.h>
-#include <linux/reboot.h>
 #include <linux/watchdog.h>
 
 #define SOFT_TIMEOUT_MIN	1
@@ -36,7 +34,6 @@
 	unsigned int		hw_algo;
 	unsigned int		hw_margin;
 	unsigned long		last_jiffies;
-	struct notifier_block	notifier;
 	struct timer_list	timer;
 	struct watchdog_device	wdd;
 };
@@ -57,7 +54,8 @@
 
 	if (priv->armed && time_after(jiffies, priv->last_jiffies +
 				      msecs_to_jiffies(wdd->timeout * 1000))) {
-		dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n");
+		dev_crit(wdd->parent,
+			 "Timer expired. System will reboot soon!\n");
 		return;
 	}
 
@@ -126,26 +124,6 @@
 	return gpio_wdt_ping(wdd);
 }
 
-static int gpio_wdt_notify_sys(struct notifier_block *nb, unsigned long code,
-			       void *unused)
-{
-	struct gpio_wdt_priv *priv = container_of(nb, struct gpio_wdt_priv,
-						  notifier);
-
-	mod_timer(&priv->timer, 0);
-
-	switch (code) {
-	case SYS_HALT:
-	case SYS_POWER_OFF:
-		gpio_wdt_disable(priv);
-		break;
-	default:
-		break;
-	}
-
-	return NOTIFY_DONE;
-}
-
 static const struct watchdog_info gpio_wdt_ident = {
 	.options	= WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING |
 			  WDIOF_SETTIMEOUT,
@@ -224,23 +202,16 @@
 
 	setup_timer(&priv->timer, gpio_wdt_hwping, (unsigned long)&priv->wdd);
 
+	watchdog_stop_on_reboot(&priv->wdd);
+
 	ret = watchdog_register_device(&priv->wdd);
 	if (ret)
 		return ret;
 
-	priv->notifier.notifier_call = gpio_wdt_notify_sys;
-	ret = register_reboot_notifier(&priv->notifier);
-	if (ret)
-		goto error_unregister;
-
 	if (priv->always_running)
 		gpio_wdt_start_impl(priv);
 
 	return 0;
-
-error_unregister:
-	watchdog_unregister_device(&priv->wdd);
-	return ret;
 }
 
 static int gpio_wdt_remove(struct platform_device *pdev)
@@ -248,7 +219,6 @@
 	struct gpio_wdt_priv *priv = platform_get_drvdata(pdev);
 
 	del_timer_sync(&priv->timer);
-	unregister_reboot_notifier(&priv->notifier);
 	watchdog_unregister_device(&priv->wdd);
 
 	return 0;
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 286369d..92443c3 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -1,11 +1,11 @@
 /*
- *	HP WatchDog Driver
+ *	HPE WatchDog Driver
  *	based on
  *
  *	SoftDog	0.05:	A Software Watchdog Device
  *
- *	(c) Copyright 2007 Hewlett-Packard Development Company, L.P.
- *	Thomas Mingarelli <thomas.mingarelli@hp.com>
+ *	(c) Copyright 2015 Hewlett Packard Enterprise Development LP
+ *	Thomas Mingarelli <thomas.mingarelli@hpe.com>
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -580,7 +580,7 @@
 	.options = WDIOF_SETTIMEOUT |
 		   WDIOF_KEEPALIVEPING |
 		   WDIOF_MAGICCLOSE,
-	.identity = "HP iLO2+ HW Watchdog Timer",
+	.identity = "HPE iLO2+ HW Watchdog Timer",
 };
 
 static long hpwdt_ioctl(struct file *file, unsigned int cmd,
@@ -758,7 +758,7 @@
 		goto error2;
 
 	dev_info(&dev->dev,
-			"HP Watchdog Timer Driver: NMI decoding initialized"
+			"HPE Watchdog Timer Driver: NMI decoding initialized"
 			", allow kernel dump: %s (default = 1/ON)\n",
 			(allow_kdump == 0) ? "OFF" : "ON");
 	return 0;
@@ -863,7 +863,7 @@
 		goto error_misc_register;
 	}
 
-	dev_info(&dev->dev, "HP Watchdog Timer Driver: %s"
+	dev_info(&dev->dev, "HPE Watchdog Timer Driver: %s"
 			", timer margin: %d seconds (nowayout=%d).\n",
 			HPWDT_VERSION, soft_margin, nowayout);
 	return 0;
diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c
index 15ab072..3679f2e 100644
--- a/drivers/watchdog/imgpdc_wdt.c
+++ b/drivers/watchdog/imgpdc_wdt.c
@@ -45,7 +45,6 @@
 #include <linux/log2.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/reboot.h>
 #include <linux/slab.h>
 #include <linux/watchdog.h>
 
@@ -87,7 +86,6 @@
 	struct clk *wdt_clk;
 	struct clk *sys_clk;
 	void __iomem *base;
-	struct notifier_block restart_handler;
 };
 
 static int pdc_wdt_keepalive(struct watchdog_device *wdt_dev)
@@ -152,6 +150,16 @@
 	return 0;
 }
 
+static int pdc_wdt_restart(struct watchdog_device *wdt_dev)
+{
+	struct pdc_wdt_dev *wdt = watchdog_get_drvdata(wdt_dev);
+
+	/* Assert SOFT_RESET */
+	writel(0x1, wdt->base + PDC_WDT_SOFT_RESET);
+
+	return 0;
+}
+
 static struct watchdog_info pdc_wdt_info = {
 	.identity	= "IMG PDC Watchdog",
 	.options	= WDIOF_SETTIMEOUT |
@@ -165,20 +173,9 @@
 	.stop		= pdc_wdt_stop,
 	.ping		= pdc_wdt_keepalive,
 	.set_timeout	= pdc_wdt_set_timeout,
+	.restart        = pdc_wdt_restart,
 };
 
-static int pdc_wdt_restart(struct notifier_block *this, unsigned long mode,
-			   void *cmd)
-{
-	struct pdc_wdt_dev *wdt = container_of(this, struct pdc_wdt_dev,
-					       restart_handler);
-
-	/* Assert SOFT_RESET */
-	writel(0x1, wdt->base + PDC_WDT_SOFT_RESET);
-
-	return NOTIFY_OK;
-}
-
 static int pdc_wdt_probe(struct platform_device *pdev)
 {
 	u64 div;
@@ -282,6 +279,7 @@
 	}
 
 	watchdog_set_nowayout(&pdc_wdt->wdt_dev, nowayout);
+	watchdog_set_restart_priority(&pdc_wdt->wdt_dev, 128);
 
 	platform_set_drvdata(pdev, pdc_wdt);
 
@@ -289,13 +287,6 @@
 	if (ret)
 		goto disable_wdt_clk;
 
-	pdc_wdt->restart_handler.notifier_call = pdc_wdt_restart;
-	pdc_wdt->restart_handler.priority = 128;
-	ret = register_restart_handler(&pdc_wdt->restart_handler);
-	if (ret)
-		dev_warn(&pdev->dev, "failed to register restart handler: %d\n",
-			 ret);
-
 	return 0;
 
 disable_wdt_clk:
@@ -316,7 +307,6 @@
 {
 	struct pdc_wdt_dev *pdc_wdt = platform_get_drvdata(pdev);
 
-	unregister_restart_handler(&pdc_wdt->restart_handler);
 	pdc_wdt_stop(&pdc_wdt->wdt_dev);
 	watchdog_unregister_device(&pdc_wdt->wdt_dev);
 	clk_disable_unprepare(pdc_wdt->wdt_clk);
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index 29ef719..e47966a 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -29,10 +29,8 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/notifier.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
-#include <linux/reboot.h>
 #include <linux/regmap.h>
 #include <linux/timer.h>
 #include <linux/watchdog.h>
@@ -64,7 +62,6 @@
 	struct regmap *regmap;
 	struct timer_list timer;	/* Pings the watchdog when closed */
 	struct watchdog_device wdog;
-	struct notifier_block restart_handler;
 };
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -83,13 +80,11 @@
 	.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
 };
 
-static int imx2_restart_handler(struct notifier_block *this, unsigned long mode,
-				void *cmd)
+static int imx2_wdt_restart(struct watchdog_device *wdog)
 {
+	struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
 	unsigned int wcr_enable = IMX2_WDT_WCR_WDE;
-	struct imx2_wdt_device *wdev = container_of(this,
-						    struct imx2_wdt_device,
-						    restart_handler);
+
 	/* Assert SRS signal */
 	regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable);
 	/*
@@ -105,7 +100,7 @@
 	/* wait for reset to assert... */
 	mdelay(500);
 
-	return NOTIFY_DONE;
+	return 0;
 }
 
 static inline void imx2_wdt_setup(struct watchdog_device *wdog)
@@ -213,6 +208,7 @@
 	.stop = imx2_wdt_stop,
 	.ping = imx2_wdt_ping,
 	.set_timeout = imx2_wdt_set_timeout,
+	.restart = imx2_wdt_restart,
 };
 
 static const struct regmap_config imx2_wdt_regmap_config = {
@@ -275,6 +271,7 @@
 	platform_set_drvdata(pdev, wdog);
 	watchdog_set_drvdata(wdog, wdev);
 	watchdog_set_nowayout(wdog, nowayout);
+	watchdog_set_restart_priority(wdog, 128);
 	watchdog_init_timeout(wdog, timeout, &pdev->dev);
 
 	setup_timer(&wdev->timer, imx2_wdt_timer_ping, (unsigned long)wdog);
@@ -294,12 +291,6 @@
 		goto disable_clk;
 	}
 
-	wdev->restart_handler.notifier_call = imx2_restart_handler;
-	wdev->restart_handler.priority = 128;
-	ret = register_restart_handler(&wdev->restart_handler);
-	if (ret)
-		dev_err(&pdev->dev, "cannot register restart handler\n");
-
 	dev_info(&pdev->dev, "timeout %d sec (nowayout=%d)\n",
 		 wdog->timeout, nowayout);
 
@@ -315,8 +306,6 @@
 	struct watchdog_device *wdog = platform_get_drvdata(pdev);
 	struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
 
-	unregister_restart_handler(&wdev->restart_handler);
-
 	watchdog_unregister_device(wdog);
 
 	if (imx2_wdt_is_running(wdev)) {
diff --git a/drivers/watchdog/lpc18xx_wdt.c b/drivers/watchdog/lpc18xx_wdt.c
index ab7b8b1..6914c83 100644
--- a/drivers/watchdog/lpc18xx_wdt.c
+++ b/drivers/watchdog/lpc18xx_wdt.c
@@ -18,7 +18,6 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
-#include <linux/reboot.h>
 #include <linux/watchdog.h>
 
 /* Registers */
@@ -59,7 +58,6 @@
 	unsigned long		clk_rate;
 	void __iomem		*base;
 	struct timer_list	timer;
-	struct notifier_block	restart_handler;
 	spinlock_t		lock;
 };
 
@@ -155,27 +153,9 @@
 	return 0;
 }
 
-static struct watchdog_info lpc18xx_wdt_info = {
-	.identity	= "NXP LPC18xx Watchdog",
-	.options	= WDIOF_SETTIMEOUT |
-			  WDIOF_KEEPALIVEPING |
-			  WDIOF_MAGICCLOSE,
-};
-
-static const struct watchdog_ops lpc18xx_wdt_ops = {
-	.owner		= THIS_MODULE,
-	.start		= lpc18xx_wdt_start,
-	.stop		= lpc18xx_wdt_stop,
-	.ping		= lpc18xx_wdt_feed,
-	.set_timeout	= lpc18xx_wdt_set_timeout,
-	.get_timeleft	= lpc18xx_wdt_get_timeleft,
-};
-
-static int lpc18xx_wdt_restart(struct notifier_block *this, unsigned long mode,
-			       void *cmd)
+static int lpc18xx_wdt_restart(struct watchdog_device *wdt_dev)
 {
-	struct lpc18xx_wdt_dev *lpc18xx_wdt = container_of(this,
-				struct lpc18xx_wdt_dev, restart_handler);
+	struct lpc18xx_wdt_dev *lpc18xx_wdt = watchdog_get_drvdata(wdt_dev);
 	unsigned long flags;
 	int val;
 
@@ -197,9 +177,26 @@
 
 	spin_unlock_irqrestore(&lpc18xx_wdt->lock, flags);
 
-	return NOTIFY_OK;
+	return 0;
 }
 
+static struct watchdog_info lpc18xx_wdt_info = {
+	.identity	= "NXP LPC18xx Watchdog",
+	.options	= WDIOF_SETTIMEOUT |
+			  WDIOF_KEEPALIVEPING |
+			  WDIOF_MAGICCLOSE,
+};
+
+static const struct watchdog_ops lpc18xx_wdt_ops = {
+	.owner		= THIS_MODULE,
+	.start		= lpc18xx_wdt_start,
+	.stop		= lpc18xx_wdt_stop,
+	.ping		= lpc18xx_wdt_feed,
+	.set_timeout	= lpc18xx_wdt_set_timeout,
+	.get_timeleft	= lpc18xx_wdt_get_timeleft,
+	.restart        = lpc18xx_wdt_restart,
+};
+
 static int lpc18xx_wdt_probe(struct platform_device *pdev)
 {
 	struct lpc18xx_wdt_dev *lpc18xx_wdt;
@@ -273,6 +270,7 @@
 		    (unsigned long)&lpc18xx_wdt->wdt_dev);
 
 	watchdog_set_nowayout(&lpc18xx_wdt->wdt_dev, nowayout);
+	watchdog_set_restart_priority(&lpc18xx_wdt->wdt_dev, 128);
 
 	platform_set_drvdata(pdev, lpc18xx_wdt);
 
@@ -280,12 +278,6 @@
 	if (ret)
 		goto disable_wdt_clk;
 
-	lpc18xx_wdt->restart_handler.notifier_call = lpc18xx_wdt_restart;
-	lpc18xx_wdt->restart_handler.priority = 128;
-	ret = register_restart_handler(&lpc18xx_wdt->restart_handler);
-	if (ret)
-		dev_warn(dev, "failed to register restart handler: %d\n", ret);
-
 	return 0;
 
 disable_wdt_clk:
@@ -306,8 +298,6 @@
 {
 	struct lpc18xx_wdt_dev *lpc18xx_wdt = platform_get_drvdata(pdev);
 
-	unregister_restart_handler(&lpc18xx_wdt->restart_handler);
-
 	dev_warn(&pdev->dev, "I quit now, hardware will probably reboot!\n");
 	del_timer(&lpc18xx_wdt->timer);
 
diff --git a/drivers/watchdog/mena21_wdt.c b/drivers/watchdog/mena21_wdt.c
index 098fa9c..af6a7c4 100644
--- a/drivers/watchdog/mena21_wdt.c
+++ b/drivers/watchdog/mena21_wdt.c
@@ -100,12 +100,12 @@
 	struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt);
 
 	if (timeout != 1 && timeout != 30) {
-		dev_err(wdt->dev, "Only 1 and 30 allowed as timeout\n");
+		dev_err(wdt->parent, "Only 1 and 30 allowed as timeout\n");
 		return -EINVAL;
 	}
 
 	if (timeout == 30 && wdt->timeout == 1) {
-		dev_err(wdt->dev,
+		dev_err(wdt->parent,
 			"Transition from fast to slow mode not allowed\n");
 		return -EINVAL;
 	}
diff --git a/drivers/watchdog/meson_wdt.c b/drivers/watchdog/meson_wdt.c
index 1f4155e..aea5d2f 100644
--- a/drivers/watchdog/meson_wdt.c
+++ b/drivers/watchdog/meson_wdt.c
@@ -17,51 +17,64 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/notifier.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
-#include <linux/reboot.h>
 #include <linux/types.h>
 #include <linux/watchdog.h>
 
 #define DRV_NAME		"meson_wdt"
 
 #define MESON_WDT_TC		0x00
-#define MESON_WDT_TC_EN		BIT(22)
-#define MESON_WDT_TC_TM_MASK	0x3fffff
 #define MESON_WDT_DC_RESET	(3 << 24)
 
 #define MESON_WDT_RESET		0x04
 
 #define MESON_WDT_TIMEOUT	30
 #define MESON_WDT_MIN_TIMEOUT	1
-#define MESON_WDT_MAX_TIMEOUT	(MESON_WDT_TC_TM_MASK / 100000)
 
-#define MESON_SEC_TO_TC(s)	((s) * 100000)
+#define MESON_SEC_TO_TC(s, c)	((s) * (c))
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
 static unsigned int timeout = MESON_WDT_TIMEOUT;
 
+struct meson_wdt_data {
+	unsigned int enable;
+	unsigned int terminal_count_mask;
+	unsigned int count_unit;
+};
+
+static struct meson_wdt_data meson6_wdt_data = {
+	.enable			= BIT(22),
+	.terminal_count_mask	= 0x3fffff,
+	.count_unit		= 100000, /* 10 us */
+};
+
+static struct meson_wdt_data meson8b_wdt_data = {
+	.enable			= BIT(19),
+	.terminal_count_mask	= 0xffff,
+	.count_unit		= 7812, /* 128 us */
+};
+
 struct meson_wdt_dev {
 	struct watchdog_device wdt_dev;
 	void __iomem *wdt_base;
-	struct notifier_block restart_handler;
+	const struct meson_wdt_data *data;
 };
 
-static int meson_restart_handle(struct notifier_block *this, unsigned long mode,
-				void *cmd)
+static int meson_wdt_restart(struct watchdog_device *wdt_dev)
 {
-	u32 tc_reboot = MESON_WDT_DC_RESET | MESON_WDT_TC_EN;
-	struct meson_wdt_dev *meson_wdt = container_of(this,
-						       struct meson_wdt_dev,
-						       restart_handler);
+	struct meson_wdt_dev *meson_wdt = watchdog_get_drvdata(wdt_dev);
+	u32 tc_reboot = MESON_WDT_DC_RESET;
+
+	tc_reboot |= meson_wdt->data->enable;
 
 	while (1) {
 		writel(tc_reboot, meson_wdt->wdt_base + MESON_WDT_TC);
 		mdelay(5);
 	}
 
-	return NOTIFY_DONE;
+	return 0;
 }
 
 static int meson_wdt_ping(struct watchdog_device *wdt_dev)
@@ -80,8 +93,8 @@
 	u32 reg;
 
 	reg = readl(meson_wdt->wdt_base + MESON_WDT_TC);
-	reg &= ~MESON_WDT_TC_TM_MASK;
-	reg |= MESON_SEC_TO_TC(timeout);
+	reg &= ~meson_wdt->data->terminal_count_mask;
+	reg |= MESON_SEC_TO_TC(timeout, meson_wdt->data->count_unit);
 	writel(reg, meson_wdt->wdt_base + MESON_WDT_TC);
 }
 
@@ -102,7 +115,7 @@
 	u32 reg;
 
 	reg = readl(meson_wdt->wdt_base + MESON_WDT_TC);
-	reg &= ~MESON_WDT_TC_EN;
+	reg &= ~meson_wdt->data->enable;
 	writel(reg, meson_wdt->wdt_base + MESON_WDT_TC);
 
 	return 0;
@@ -117,7 +130,7 @@
 	meson_wdt_ping(wdt_dev);
 
 	reg = readl(meson_wdt->wdt_base + MESON_WDT_TC);
-	reg |= MESON_WDT_TC_EN;
+	reg |= meson_wdt->data->enable;
 	writel(reg, meson_wdt->wdt_base + MESON_WDT_TC);
 
 	return 0;
@@ -136,12 +149,21 @@
 	.stop		= meson_wdt_stop,
 	.ping		= meson_wdt_ping,
 	.set_timeout	= meson_wdt_set_timeout,
+	.restart        = meson_wdt_restart,
 };
 
+static const struct of_device_id meson_wdt_dt_ids[] = {
+	{ .compatible = "amlogic,meson6-wdt", .data = &meson6_wdt_data },
+	{ .compatible = "amlogic,meson8b-wdt", .data = &meson8b_wdt_data },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, meson_wdt_dt_ids);
+
 static int meson_wdt_probe(struct platform_device *pdev)
 {
 	struct resource *res;
 	struct meson_wdt_dev *meson_wdt;
+	const struct of_device_id *of_id;
 	int err;
 
 	meson_wdt = devm_kzalloc(&pdev->dev, sizeof(*meson_wdt), GFP_KERNEL);
@@ -153,17 +175,28 @@
 	if (IS_ERR(meson_wdt->wdt_base))
 		return PTR_ERR(meson_wdt->wdt_base);
 
+	of_id = of_match_device(meson_wdt_dt_ids, &pdev->dev);
+	if (!of_id) {
+		dev_err(&pdev->dev, "Unable to initialize WDT data\n");
+		return -ENODEV;
+	}
+	meson_wdt->data = of_id->data;
+
 	meson_wdt->wdt_dev.parent = &pdev->dev;
 	meson_wdt->wdt_dev.info = &meson_wdt_info;
 	meson_wdt->wdt_dev.ops = &meson_wdt_ops;
-	meson_wdt->wdt_dev.timeout = MESON_WDT_TIMEOUT;
-	meson_wdt->wdt_dev.max_timeout = MESON_WDT_MAX_TIMEOUT;
+	meson_wdt->wdt_dev.max_timeout =
+		meson_wdt->data->terminal_count_mask / meson_wdt->data->count_unit;
 	meson_wdt->wdt_dev.min_timeout = MESON_WDT_MIN_TIMEOUT;
+	meson_wdt->wdt_dev.timeout = min_t(unsigned int,
+					   MESON_WDT_TIMEOUT,
+					   meson_wdt->wdt_dev.max_timeout);
 
 	watchdog_set_drvdata(&meson_wdt->wdt_dev, meson_wdt);
 
 	watchdog_init_timeout(&meson_wdt->wdt_dev, timeout, &pdev->dev);
 	watchdog_set_nowayout(&meson_wdt->wdt_dev, nowayout);
+	watchdog_set_restart_priority(&meson_wdt->wdt_dev, 128);
 
 	meson_wdt_stop(&meson_wdt->wdt_dev);
 
@@ -173,13 +206,6 @@
 
 	platform_set_drvdata(pdev, meson_wdt);
 
-	meson_wdt->restart_handler.notifier_call = meson_restart_handle;
-	meson_wdt->restart_handler.priority = 128;
-	err = register_restart_handler(&meson_wdt->restart_handler);
-	if (err)
-		dev_err(&pdev->dev,
-			"cannot register restart handler (err=%d)\n", err);
-
 	dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)",
 		 meson_wdt->wdt_dev.timeout, nowayout);
 
@@ -190,8 +216,6 @@
 {
 	struct meson_wdt_dev *meson_wdt = platform_get_drvdata(pdev);
 
-	unregister_restart_handler(&meson_wdt->restart_handler);
-
 	watchdog_unregister_device(&meson_wdt->wdt_dev);
 
 	return 0;
@@ -204,12 +228,6 @@
 	meson_wdt_stop(&meson_wdt->wdt_dev);
 }
 
-static const struct of_device_id meson_wdt_dt_ids[] = {
-	{ .compatible = "amlogic,meson6-wdt" },
-	{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, meson_wdt_dt_ids);
-
 static struct platform_driver meson_wdt_driver = {
 	.probe		= meson_wdt_probe,
 	.remove		= meson_wdt_remove,
diff --git a/drivers/watchdog/moxart_wdt.c b/drivers/watchdog/moxart_wdt.c
index 60b0605..885c81b 100644
--- a/drivers/watchdog/moxart_wdt.c
+++ b/drivers/watchdog/moxart_wdt.c
@@ -15,9 +15,7 @@
 #include <linux/module.h>
 #include <linux/err.h>
 #include <linux/kernel.h>
-#include <linux/notifier.h>
 #include <linux/platform_device.h>
-#include <linux/reboot.h>
 #include <linux/watchdog.h>
 #include <linux/moduleparam.h>
 
@@ -29,22 +27,19 @@
 	struct watchdog_device dev;
 	void __iomem *base;
 	unsigned int clock_frequency;
-	struct notifier_block restart_handler;
 };
 
 static int heartbeat;
 
-static int moxart_restart_handle(struct notifier_block *this,
-				 unsigned long mode, void *cmd)
+static int moxart_wdt_restart(struct watchdog_device *wdt_dev)
 {
-	struct moxart_wdt_dev *moxart_wdt = container_of(this,
-							 struct moxart_wdt_dev,
-							 restart_handler);
+	struct moxart_wdt_dev *moxart_wdt = watchdog_get_drvdata(wdt_dev);
+
 	writel(1, moxart_wdt->base + REG_COUNT);
 	writel(0x5ab9, moxart_wdt->base + REG_MODE);
 	writel(0x03, moxart_wdt->base + REG_ENABLE);
 
-	return NOTIFY_DONE;
+	return 0;
 }
 
 static int moxart_wdt_stop(struct watchdog_device *wdt_dev)
@@ -87,6 +82,7 @@
 	.start          = moxart_wdt_start,
 	.stop           = moxart_wdt_stop,
 	.set_timeout    = moxart_wdt_set_timeout,
+	.restart        = moxart_wdt_restart,
 };
 
 static int moxart_wdt_probe(struct platform_device *pdev)
@@ -134,6 +130,7 @@
 
 	watchdog_init_timeout(&moxart_wdt->dev, heartbeat, dev);
 	watchdog_set_nowayout(&moxart_wdt->dev, nowayout);
+	watchdog_set_restart_priority(&moxart_wdt->dev, 128);
 
 	watchdog_set_drvdata(&moxart_wdt->dev, moxart_wdt);
 
@@ -141,13 +138,6 @@
 	if (err)
 		return err;
 
-	moxart_wdt->restart_handler.notifier_call = moxart_restart_handle;
-	moxart_wdt->restart_handler.priority = 128;
-	err = register_restart_handler(&moxart_wdt->restart_handler);
-	if (err)
-		dev_err(dev, "cannot register restart notifier (err=%d)\n",
-			err);
-
 	dev_dbg(dev, "Watchdog enabled (heartbeat=%d sec, nowayout=%d)\n",
 		moxart_wdt->dev.timeout, nowayout);
 
@@ -158,7 +148,6 @@
 {
 	struct moxart_wdt_dev *moxart_wdt = platform_get_drvdata(pdev);
 
-	unregister_restart_handler(&moxart_wdt->restart_handler);
 	moxart_wdt_stop(&moxart_wdt->dev);
 
 	return 0;
diff --git a/drivers/watchdog/mt7621_wdt.c b/drivers/watchdog/mt7621_wdt.c
new file mode 100644
index 0000000..4a2290f
--- /dev/null
+++ b/drivers/watchdog/mt7621_wdt.c
@@ -0,0 +1,186 @@
+/*
+ * Ralink MT7621/MT7628 built-in hardware watchdog timer
+ *
+ * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
+ *
+ * This driver was based on: drivers/watchdog/rt2880_wdt.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/clk.h>
+#include <linux/reset.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/watchdog.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+
+#define SYSC_RSTSTAT			0x38
+#define WDT_RST_CAUSE			BIT(1)
+
+#define RALINK_WDT_TIMEOUT		30
+
+#define TIMER_REG_TMRSTAT		0x00
+#define TIMER_REG_TMR1LOAD		0x24
+#define TIMER_REG_TMR1CTL		0x20
+
+#define TMR1CTL_ENABLE			BIT(7)
+#define TMR1CTL_RESTART			BIT(9)
+#define TMR1CTL_PRESCALE_SHIFT		16
+
+static void __iomem *mt7621_wdt_base;
+static struct reset_control *mt7621_wdt_reset;
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+		 "Watchdog cannot be stopped once started (default="
+		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static inline void rt_wdt_w32(unsigned reg, u32 val)
+{
+	iowrite32(val, mt7621_wdt_base + reg);
+}
+
+static inline u32 rt_wdt_r32(unsigned reg)
+{
+	return ioread32(mt7621_wdt_base + reg);
+}
+
+static int mt7621_wdt_ping(struct watchdog_device *w)
+{
+	rt_wdt_w32(TIMER_REG_TMRSTAT, TMR1CTL_RESTART);
+
+	return 0;
+}
+
+static int mt7621_wdt_set_timeout(struct watchdog_device *w, unsigned int t)
+{
+	w->timeout = t;
+	rt_wdt_w32(TIMER_REG_TMR1LOAD, t * 1000);
+	mt7621_wdt_ping(w);
+
+	return 0;
+}
+
+static int mt7621_wdt_start(struct watchdog_device *w)
+{
+	u32 t;
+
+	/* set the prescaler to 1ms == 1000us */
+	rt_wdt_w32(TIMER_REG_TMR1CTL, 1000 << TMR1CTL_PRESCALE_SHIFT);
+
+	mt7621_wdt_set_timeout(w, w->timeout);
+
+	t = rt_wdt_r32(TIMER_REG_TMR1CTL);
+	t |= TMR1CTL_ENABLE;
+	rt_wdt_w32(TIMER_REG_TMR1CTL, t);
+
+	return 0;
+}
+
+static int mt7621_wdt_stop(struct watchdog_device *w)
+{
+	u32 t;
+
+	mt7621_wdt_ping(w);
+
+	t = rt_wdt_r32(TIMER_REG_TMR1CTL);
+	t &= ~TMR1CTL_ENABLE;
+	rt_wdt_w32(TIMER_REG_TMR1CTL, t);
+
+	return 0;
+}
+
+static int mt7621_wdt_bootcause(void)
+{
+	if (rt_sysc_r32(SYSC_RSTSTAT) & WDT_RST_CAUSE)
+		return WDIOF_CARDRESET;
+
+	return 0;
+}
+
+static struct watchdog_info mt7621_wdt_info = {
+	.identity = "Mediatek Watchdog",
+	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+};
+
+static struct watchdog_ops mt7621_wdt_ops = {
+	.owner = THIS_MODULE,
+	.start = mt7621_wdt_start,
+	.stop = mt7621_wdt_stop,
+	.ping = mt7621_wdt_ping,
+	.set_timeout = mt7621_wdt_set_timeout,
+};
+
+static struct watchdog_device mt7621_wdt_dev = {
+	.info = &mt7621_wdt_info,
+	.ops = &mt7621_wdt_ops,
+	.min_timeout = 1,
+	.max_timeout = 0xfffful / 1000,
+};
+
+static int mt7621_wdt_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mt7621_wdt_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(mt7621_wdt_base))
+		return PTR_ERR(mt7621_wdt_base);
+
+	mt7621_wdt_reset = devm_reset_control_get(&pdev->dev, NULL);
+	if (!IS_ERR(mt7621_wdt_reset))
+		reset_control_deassert(mt7621_wdt_reset);
+
+	mt7621_wdt_dev.dev = &pdev->dev;
+	mt7621_wdt_dev.bootstatus = mt7621_wdt_bootcause();
+
+	watchdog_init_timeout(&mt7621_wdt_dev, mt7621_wdt_dev.max_timeout,
+			      &pdev->dev);
+	watchdog_set_nowayout(&mt7621_wdt_dev, nowayout);
+
+	ret = watchdog_register_device(&mt7621_wdt_dev);
+
+	return 0;
+}
+
+static int mt7621_wdt_remove(struct platform_device *pdev)
+{
+	watchdog_unregister_device(&mt7621_wdt_dev);
+
+	return 0;
+}
+
+static void mt7621_wdt_shutdown(struct platform_device *pdev)
+{
+	mt7621_wdt_stop(&mt7621_wdt_dev);
+}
+
+static const struct of_device_id mt7621_wdt_match[] = {
+	{ .compatible = "mediatek,mt7621-wdt" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mt7621_wdt_match);
+
+static struct platform_driver mt7621_wdt_driver = {
+	.probe		= mt7621_wdt_probe,
+	.remove		= mt7621_wdt_remove,
+	.shutdown	= mt7621_wdt_shutdown,
+	.driver		= {
+		.name		= KBUILD_MODNAME,
+		.of_match_table	= mt7621_wdt_match,
+	},
+};
+
+module_platform_driver(mt7621_wdt_driver);
+
+MODULE_DESCRIPTION("MediaTek MT762x hardware watchdog driver");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
index b751f43..b78776c 100644
--- a/drivers/watchdog/mtk_wdt.c
+++ b/drivers/watchdog/mtk_wdt.c
@@ -28,8 +28,6 @@
 #include <linux/platform_device.h>
 #include <linux/types.h>
 #include <linux/watchdog.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
 #include <linux/delay.h>
 
 #define WDT_MAX_TIMEOUT		31
@@ -64,16 +62,13 @@
 struct mtk_wdt_dev {
 	struct watchdog_device wdt_dev;
 	void __iomem *wdt_base;
-	struct notifier_block restart_handler;
 };
 
-static int mtk_reset_handler(struct notifier_block *this, unsigned long mode,
-				void *cmd)
+static int mtk_wdt_restart(struct watchdog_device *wdt_dev)
 {
-	struct mtk_wdt_dev *mtk_wdt;
+	struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
 	void __iomem *wdt_base;
 
-	mtk_wdt = container_of(this, struct mtk_wdt_dev, restart_handler);
 	wdt_base = mtk_wdt->wdt_base;
 
 	while (1) {
@@ -81,7 +76,7 @@
 		mdelay(5);
 	}
 
-	return NOTIFY_DONE;
+	return 0;
 }
 
 static int mtk_wdt_ping(struct watchdog_device *wdt_dev)
@@ -161,6 +156,7 @@
 	.stop		= mtk_wdt_stop,
 	.ping		= mtk_wdt_ping,
 	.set_timeout	= mtk_wdt_set_timeout,
+	.restart	= mtk_wdt_restart,
 };
 
 static int mtk_wdt_probe(struct platform_device *pdev)
@@ -189,6 +185,7 @@
 
 	watchdog_init_timeout(&mtk_wdt->wdt_dev, timeout, &pdev->dev);
 	watchdog_set_nowayout(&mtk_wdt->wdt_dev, nowayout);
+	watchdog_set_restart_priority(&mtk_wdt->wdt_dev, 128);
 
 	watchdog_set_drvdata(&mtk_wdt->wdt_dev, mtk_wdt);
 
@@ -198,13 +195,6 @@
 	if (unlikely(err))
 		return err;
 
-	mtk_wdt->restart_handler.notifier_call = mtk_reset_handler;
-	mtk_wdt->restart_handler.priority = 128;
-	err = register_restart_handler(&mtk_wdt->restart_handler);
-	if (err)
-		dev_warn(&pdev->dev,
-			"cannot register restart handler (err=%d)\n", err);
-
 	dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n",
 			mtk_wdt->wdt_dev.timeout, nowayout);
 
@@ -223,8 +213,6 @@
 {
 	struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev);
 
-	unregister_restart_handler(&mtk_wdt->restart_handler);
-
 	watchdog_unregister_device(&mtk_wdt->wdt_dev);
 
 	return 0;
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 6f17c93..1b02bfa 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -271,7 +271,8 @@
 			wdev->wdog.bootstatus = WDIOF_CARDRESET;
 	}
 
-	omap_wdt_disable(wdev);
+	if (!early_enable)
+		omap_wdt_disable(wdev);
 
 	ret = watchdog_register_device(&wdev->wdog);
 	if (ret) {
@@ -283,11 +284,11 @@
 		readl_relaxed(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
 		wdev->wdog.timeout);
 
-	pm_runtime_put_sync(wdev->dev);
-
 	if (early_enable)
 		omap_wdt_start(&wdev->wdog);
 
+	pm_runtime_put(wdev->dev);
+
 	return 0;
 }
 
diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c
index 773dcfa..424f9a9 100644
--- a/drivers/watchdog/qcom-wdt.c
+++ b/drivers/watchdog/qcom-wdt.c
@@ -17,7 +17,6 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
-#include <linux/reboot.h>
 #include <linux/watchdog.h>
 
 #define WDT_RST		0x38
@@ -28,7 +27,6 @@
 	struct watchdog_device	wdd;
 	struct clk		*clk;
 	unsigned long		rate;
-	struct notifier_block	restart_nb;
 	void __iomem		*base;
 };
 
@@ -72,25 +70,9 @@
 	return qcom_wdt_start(wdd);
 }
 
-static const struct watchdog_ops qcom_wdt_ops = {
-	.start		= qcom_wdt_start,
-	.stop		= qcom_wdt_stop,
-	.ping		= qcom_wdt_ping,
-	.set_timeout	= qcom_wdt_set_timeout,
-	.owner		= THIS_MODULE,
-};
-
-static const struct watchdog_info qcom_wdt_info = {
-	.options	= WDIOF_KEEPALIVEPING
-			| WDIOF_MAGICCLOSE
-			| WDIOF_SETTIMEOUT,
-	.identity	= KBUILD_MODNAME,
-};
-
-static int qcom_wdt_restart(struct notifier_block *nb, unsigned long action,
-			    void *data)
+static int qcom_wdt_restart(struct watchdog_device *wdd)
 {
-	struct qcom_wdt *wdt = container_of(nb, struct qcom_wdt, restart_nb);
+	struct qcom_wdt *wdt = to_qcom_wdt(wdd);
 	u32 timeout;
 
 	/*
@@ -110,9 +92,25 @@
 	wmb();
 
 	msleep(150);
-	return NOTIFY_DONE;
+	return 0;
 }
 
+static const struct watchdog_ops qcom_wdt_ops = {
+	.start		= qcom_wdt_start,
+	.stop		= qcom_wdt_stop,
+	.ping		= qcom_wdt_ping,
+	.set_timeout	= qcom_wdt_set_timeout,
+	.restart        = qcom_wdt_restart,
+	.owner		= THIS_MODULE,
+};
+
+static const struct watchdog_info qcom_wdt_info = {
+	.options	= WDIOF_KEEPALIVEPING
+			| WDIOF_MAGICCLOSE
+			| WDIOF_SETTIMEOUT,
+	.identity	= KBUILD_MODNAME,
+};
+
 static int qcom_wdt_probe(struct platform_device *pdev)
 {
 	struct qcom_wdt *wdt;
@@ -166,7 +164,6 @@
 		goto err_clk_unprepare;
 	}
 
-	wdt->wdd.dev = &pdev->dev;
 	wdt->wdd.info = &qcom_wdt_info;
 	wdt->wdd.ops = &qcom_wdt_ops;
 	wdt->wdd.min_timeout = 1;
@@ -187,14 +184,6 @@
 		goto err_clk_unprepare;
 	}
 
-	/*
-	 * WDT restart notifier has priority 0 (use as a last resort)
-	 */
-	wdt->restart_nb.notifier_call = qcom_wdt_restart;
-	ret = register_restart_handler(&wdt->restart_nb);
-	if (ret)
-		dev_err(&pdev->dev, "failed to setup restart handler\n");
-
 	platform_set_drvdata(pdev, wdt);
 	return 0;
 
@@ -207,7 +196,6 @@
 {
 	struct qcom_wdt *wdt = platform_get_drvdata(pdev);
 
-	unregister_restart_handler(&wdt->restart_nb);
 	watchdog_unregister_device(&wdt->wdd);
 	clk_disable_unprepare(wdt->clk);
 	return 0;
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index d781000..0093450 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -41,7 +41,6 @@
 #include <linux/of.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
-#include <linux/reboot.h>
 #include <linux/delay.h>
 
 #define S3C2410_WTCON		0x00
@@ -130,7 +129,6 @@
 	unsigned long		wtdat_save;
 	struct watchdog_device	wdt_device;
 	struct notifier_block	freq_transition;
-	struct notifier_block	restart_handler;
 	struct s3c2410_wdt_variant *drv_data;
 	struct regmap *pmureg;
 };
@@ -351,6 +349,29 @@
 	return 0;
 }
 
+static int s3c2410wdt_restart(struct watchdog_device *wdd)
+{
+	struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
+	void __iomem *wdt_base = wdt->reg_base;
+
+	/* disable watchdog, to be safe  */
+	writel(0, wdt_base + S3C2410_WTCON);
+
+	/* put initial values into count and data */
+	writel(0x80, wdt_base + S3C2410_WTCNT);
+	writel(0x80, wdt_base + S3C2410_WTDAT);
+
+	/* set the watchdog to go and reset... */
+	writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV16 |
+		S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x20),
+		wdt_base + S3C2410_WTCON);
+
+	/* wait for reset to assert... */
+	mdelay(500);
+
+	return 0;
+}
+
 #define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)
 
 static const struct watchdog_info s3c2410_wdt_ident = {
@@ -365,6 +386,7 @@
 	.stop = s3c2410wdt_stop,
 	.ping = s3c2410wdt_keepalive,
 	.set_timeout = s3c2410wdt_set_heartbeat,
+	.restart = s3c2410wdt_restart,
 };
 
 static struct watchdog_device s3c2410_wdd = {
@@ -452,31 +474,6 @@
 }
 #endif
 
-static int s3c2410wdt_restart(struct notifier_block *this,
-			      unsigned long mode, void *cmd)
-{
-	struct s3c2410_wdt *wdt = container_of(this, struct s3c2410_wdt,
-					       restart_handler);
-	void __iomem *wdt_base = wdt->reg_base;
-
-	/* disable watchdog, to be safe  */
-	writel(0, wdt_base + S3C2410_WTCON);
-
-	/* put initial values into count and data */
-	writel(0x80, wdt_base + S3C2410_WTCNT);
-	writel(0x80, wdt_base + S3C2410_WTDAT);
-
-	/* set the watchdog to go and reset... */
-	writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV16 |
-		S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x20),
-		wdt_base + S3C2410_WTCON);
-
-	/* wait for reset to assert... */
-	mdelay(500);
-
-	return NOTIFY_DONE;
-}
-
 static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt)
 {
 	unsigned int rst_stat;
@@ -605,6 +602,7 @@
 	}
 
 	watchdog_set_nowayout(&wdt->wdt_device, nowayout);
+	watchdog_set_restart_priority(&wdt->wdt_device, 128);
 
 	wdt->wdt_device.bootstatus = s3c2410wdt_get_bootstatus(wdt);
 	wdt->wdt_device.parent = &pdev->dev;
@@ -632,12 +630,6 @@
 
 	platform_set_drvdata(pdev, wdt);
 
-	wdt->restart_handler.notifier_call = s3c2410wdt_restart;
-	wdt->restart_handler.priority = 128;
-	ret = register_restart_handler(&wdt->restart_handler);
-	if (ret)
-		pr_err("cannot register restart handler, %d\n", ret);
-
 	/* print out a statement of readiness */
 
 	wtcon = readl(wdt->reg_base + S3C2410_WTCON);
@@ -667,8 +659,6 @@
 	int ret;
 	struct s3c2410_wdt *wdt = platform_get_drvdata(dev);
 
-	unregister_restart_handler(&wdt->restart_handler);
-
 	ret = s3c2410wdt_mask_and_disable_reset(wdt, true);
 	if (ret < 0)
 		return ret;
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c
index 0dc5e323d..99a06f9 100644
--- a/drivers/watchdog/softdog.c
+++ b/drivers/watchdog/softdog.c
@@ -43,7 +43,6 @@
 #include <linux/types.h>
 #include <linux/timer.h>
 #include <linux/watchdog.h>
-#include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/jiffies.h>
@@ -87,6 +86,7 @@
 
 static void watchdog_fire(unsigned long data)
 {
+	module_put(THIS_MODULE);
 	if (soft_noboot)
 		pr_crit("Triggered - Reboot ignored\n");
 	else if (soft_panic) {
@@ -105,13 +105,16 @@
 
 static int softdog_ping(struct watchdog_device *w)
 {
-	mod_timer(&watchdog_ticktock, jiffies+(w->timeout*HZ));
+	if (!mod_timer(&watchdog_ticktock, jiffies+(w->timeout*HZ)))
+		__module_get(THIS_MODULE);
 	return 0;
 }
 
 static int softdog_stop(struct watchdog_device *w)
 {
-	del_timer(&watchdog_ticktock);
+	if (del_timer(&watchdog_ticktock))
+		module_put(THIS_MODULE);
+
 	return 0;
 }
 
@@ -122,26 +125,9 @@
 }
 
 /*
- *	Notifier for system down
- */
-
-static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
-	void *unused)
-{
-	if (code == SYS_DOWN || code == SYS_HALT)
-		/* Turn the WDT off */
-		softdog_stop(NULL);
-	return NOTIFY_DONE;
-}
-
-/*
  *	Kernel Interfaces
  */
 
-static struct notifier_block softdog_notifier = {
-	.notifier_call	= softdog_notify_sys,
-};
-
 static struct watchdog_info softdog_info = {
 	.identity = "Software Watchdog",
 	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
@@ -175,18 +161,11 @@
 	softdog_dev.timeout = soft_margin;
 
 	watchdog_set_nowayout(&softdog_dev, nowayout);
-
-	ret = register_reboot_notifier(&softdog_notifier);
-	if (ret) {
-		pr_err("cannot register reboot notifier (err=%d)\n", ret);
-		return ret;
-	}
+	watchdog_stop_on_reboot(&softdog_dev);
 
 	ret = watchdog_register_device(&softdog_dev);
-	if (ret) {
-		unregister_reboot_notifier(&softdog_notifier);
+	if (ret)
 		return ret;
-	}
 
 	pr_info("Software Watchdog Timer: 0.08 initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d (nowayout=%d)\n",
 		soft_noboot, soft_margin, soft_panic, nowayout);
@@ -197,7 +176,6 @@
 static void __exit watchdog_exit(void)
 {
 	watchdog_unregister_device(&softdog_dev);
-	unregister_reboot_notifier(&softdog_notifier);
 }
 
 module_init(watchdog_init);
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
index eb8044e..6467b91 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -306,6 +306,10 @@
 static const struct pci_device_id sp5100_tco_pci_tbl[] = {
 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_ANY_ID,
 	  PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, PCI_ANY_ID,
+	  PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_KERNCZ_SMBUS, PCI_ANY_ID,
+	  PCI_ANY_ID, },
 	{ 0, },			/* End of list */
 };
 MODULE_DEVICE_TABLE(pci, sp5100_tco_pci_tbl);
@@ -331,21 +335,24 @@
 	if (!sp5100_tco_pci)
 		return 0;
 
-	pr_info("PCI Revision ID: 0x%x\n", sp5100_tco_pci->revision);
+	pr_info("PCI Vendor ID: 0x%x, Device ID: 0x%x, Revision ID: 0x%x\n",
+		sp5100_tco_pci->vendor, sp5100_tco_pci->device,
+		sp5100_tco_pci->revision);
 
 	/*
 	 * Determine type of southbridge chipset.
 	 */
-	if (sp5100_tco_pci->revision >= 0x40) {
-		dev_name = SB800_DEVNAME;
-		index_reg = SB800_IO_PM_INDEX_REG;
-		data_reg = SB800_IO_PM_DATA_REG;
-		base_addr = SB800_PM_WATCHDOG_BASE;
-	} else {
+	if (sp5100_tco_pci->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
+	    sp5100_tco_pci->revision < 0x40) {
 		dev_name = SP5100_DEVNAME;
 		index_reg = SP5100_IO_PM_INDEX_REG;
 		data_reg = SP5100_IO_PM_DATA_REG;
 		base_addr = SP5100_PM_WATCHDOG_BASE;
+	} else {
+		dev_name = SB800_DEVNAME;
+		index_reg = SB800_IO_PM_INDEX_REG;
+		data_reg = SB800_IO_PM_DATA_REG;
+		base_addr = SB800_PM_WATCHDOG_BASE;
 	}
 
 	/* Request the IO ports used by this driver */
@@ -381,7 +388,12 @@
 	 * Secondly, Find the watchdog timer MMIO address
 	 * from SBResource_MMIO register.
 	 */
-	if (sp5100_tco_pci->revision >= 0x40) {
+	if (sp5100_tco_pci->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
+	    sp5100_tco_pci->revision < 0x40) {
+		/* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
+		pci_read_config_dword(sp5100_tco_pci,
+				      SP5100_SB_RESOURCE_MMIO_BASE, &val);
+	} else {
 		/* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */
 		outb(SB800_PM_ACPI_MMIO_EN+3, SB800_IO_PM_INDEX_REG);
 		val = inb(SB800_IO_PM_DATA_REG);
@@ -391,10 +403,6 @@
 		val = val << 8 | inb(SB800_IO_PM_DATA_REG);
 		outb(SB800_PM_ACPI_MMIO_EN+0, SB800_IO_PM_INDEX_REG);
 		val = val << 8 | inb(SB800_IO_PM_DATA_REG);
-	} else {
-		/* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
-		pci_read_config_dword(sp5100_tco_pci,
-				      SP5100_SB_RESOURCE_MMIO_BASE, &val);
 	}
 
 	/* The SBResource_MMIO is enabled and mapped memory space? */
diff --git a/drivers/watchdog/stmp3xxx_rtc_wdt.c b/drivers/watchdog/stmp3xxx_rtc_wdt.c
index 3ee6128..d8b11eb 100644
--- a/drivers/watchdog/stmp3xxx_rtc_wdt.c
+++ b/drivers/watchdog/stmp3xxx_rtc_wdt.c
@@ -14,6 +14,8 @@
 #include <linux/watchdog.h>
 #include <linux/platform_device.h>
 #include <linux/stmp3xxx_rtc_wdt.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
 
 #define WDOG_TICK_RATE 1000 /* 1 kHz clock */
 #define STMP3XXX_DEFAULT_TIMEOUT 19
@@ -69,6 +71,25 @@
 	.status = WATCHDOG_NOWAYOUT_INIT_STATUS,
 };
 
+static int wdt_notify_sys(struct notifier_block *nb, unsigned long code,
+			  void *unused)
+{
+	switch (code) {
+	case SYS_DOWN:	/* keep enabled, system might crash while going down */
+		break;
+	case SYS_HALT:	/* allow the system to actually halt */
+	case SYS_POWER_OFF:
+		wdt_stop(&stmp3xxx_wdd);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block wdt_notifier = {
+	.notifier_call = wdt_notify_sys,
+};
+
 static int stmp3xxx_wdt_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -84,6 +105,9 @@
 		return ret;
 	}
 
+	if (register_reboot_notifier(&wdt_notifier))
+		dev_warn(&pdev->dev, "cannot register reboot notifier\n");
+
 	dev_info(&pdev->dev, "initialized watchdog with heartbeat %ds\n",
 			stmp3xxx_wdd.timeout);
 	return 0;
@@ -91,6 +115,7 @@
 
 static int stmp3xxx_wdt_remove(struct platform_device *pdev)
 {
+	unregister_reboot_notifier(&wdt_notifier);
 	watchdog_unregister_device(&stmp3xxx_wdd);
 	return 0;
 }
diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c
index 47bd8a1..e027deb 100644
--- a/drivers/watchdog/sunxi_wdt.c
+++ b/drivers/watchdog/sunxi_wdt.c
@@ -21,11 +21,9 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/notifier.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
-#include <linux/reboot.h>
 #include <linux/types.h>
 #include <linux/watchdog.h>
 
@@ -60,7 +58,6 @@
 	struct watchdog_device wdt_dev;
 	void __iomem *wdt_base;
 	const struct sunxi_wdt_reg *wdt_regs;
-	struct notifier_block restart_handler;
 };
 
 /*
@@ -86,12 +83,9 @@
 };
 
 
-static int sunxi_restart_handle(struct notifier_block *this, unsigned long mode,
-				void *cmd)
+static int sunxi_wdt_restart(struct watchdog_device *wdt_dev)
 {
-	struct sunxi_wdt_dev *sunxi_wdt = container_of(this,
-						       struct sunxi_wdt_dev,
-						       restart_handler);
+	struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev);
 	void __iomem *wdt_base = sunxi_wdt->wdt_base;
 	const struct sunxi_wdt_reg *regs = sunxi_wdt->wdt_regs;
 	u32 val;
@@ -120,7 +114,7 @@
 		val |= WDT_MODE_EN;
 		writel(val, wdt_base + regs->wdt_mode);
 	}
-	return NOTIFY_DONE;
+	return 0;
 }
 
 static int sunxi_wdt_ping(struct watchdog_device *wdt_dev)
@@ -208,6 +202,7 @@
 	.stop		= sunxi_wdt_stop,
 	.ping		= sunxi_wdt_ping,
 	.set_timeout	= sunxi_wdt_set_timeout,
+	.restart	= sunxi_wdt_restart,
 };
 
 static const struct sunxi_wdt_reg sun4i_wdt_reg = {
@@ -268,6 +263,7 @@
 
 	watchdog_init_timeout(&sunxi_wdt->wdt_dev, timeout, &pdev->dev);
 	watchdog_set_nowayout(&sunxi_wdt->wdt_dev, nowayout);
+	watchdog_set_restart_priority(&sunxi_wdt->wdt_dev, 128);
 
 	watchdog_set_drvdata(&sunxi_wdt->wdt_dev, sunxi_wdt);
 
@@ -277,13 +273,6 @@
 	if (unlikely(err))
 		return err;
 
-	sunxi_wdt->restart_handler.notifier_call = sunxi_restart_handle;
-	sunxi_wdt->restart_handler.priority = 128;
-	err = register_restart_handler(&sunxi_wdt->restart_handler);
-	if (err)
-		dev_err(&pdev->dev,
-			"cannot register restart handler (err=%d)\n", err);
-
 	dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)",
 			sunxi_wdt->wdt_dev.timeout, nowayout);
 
@@ -294,8 +283,6 @@
 {
 	struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev);
 
-	unregister_restart_handler(&sunxi_wdt->restart_handler);
-
 	watchdog_unregister_device(&sunxi_wdt->wdt_dev);
 	watchdog_set_drvdata(&sunxi_wdt->wdt_dev, NULL);
 
diff --git a/drivers/watchdog/tangox_wdt.c b/drivers/watchdog/tangox_wdt.c
new file mode 100644
index 0000000..709c1ed
--- /dev/null
+++ b/drivers/watchdog/tangox_wdt.c
@@ -0,0 +1,225 @@
+/*
+ *  Copyright (C) 2015 Mans Rullgard <mans@mansr.com>
+ *  SMP86xx/SMP87xx Watchdog driver
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under  the terms of the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/watchdog.h>
+
+#define DEFAULT_TIMEOUT 30
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+		 "Watchdog cannot be stopped once started (default="
+		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static unsigned int timeout;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout");
+
+/*
+ * Counter counts down from programmed value.  Reset asserts when
+ * the counter reaches 1.
+ */
+#define WD_COUNTER		0
+
+#define WD_CONFIG		4
+#define WD_CONFIG_XTAL_IN	BIT(0)
+#define WD_CONFIG_DISABLE	BIT(31)
+
+struct tangox_wdt_device {
+	struct watchdog_device wdt;
+	void __iomem *base;
+	unsigned long clk_rate;
+	struct clk *clk;
+	struct notifier_block restart;
+};
+
+static int tangox_wdt_set_timeout(struct watchdog_device *wdt,
+				  unsigned int new_timeout)
+{
+	wdt->timeout = new_timeout;
+
+	return 0;
+}
+
+static int tangox_wdt_start(struct watchdog_device *wdt)
+{
+	struct tangox_wdt_device *dev = watchdog_get_drvdata(wdt);
+	u32 ticks;
+
+	ticks = 1 + wdt->timeout * dev->clk_rate;
+	writel(ticks, dev->base + WD_COUNTER);
+
+	return 0;
+}
+
+static int tangox_wdt_stop(struct watchdog_device *wdt)
+{
+	struct tangox_wdt_device *dev = watchdog_get_drvdata(wdt);
+
+	writel(0, dev->base + WD_COUNTER);
+
+	return 0;
+}
+
+static unsigned int tangox_wdt_get_timeleft(struct watchdog_device *wdt)
+{
+	struct tangox_wdt_device *dev = watchdog_get_drvdata(wdt);
+	u32 count;
+
+	count = readl(dev->base + WD_COUNTER);
+
+	if (!count)
+		return 0;
+
+	return (count - 1) / dev->clk_rate;
+}
+
+static const struct watchdog_info tangox_wdt_info = {
+	.options  = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+	.identity = "tangox watchdog",
+};
+
+static const struct watchdog_ops tangox_wdt_ops = {
+	.start		= tangox_wdt_start,
+	.stop		= tangox_wdt_stop,
+	.set_timeout	= tangox_wdt_set_timeout,
+	.get_timeleft	= tangox_wdt_get_timeleft,
+};
+
+static int tangox_wdt_restart(struct notifier_block *nb, unsigned long action,
+			      void *data)
+{
+	struct tangox_wdt_device *dev =
+		container_of(nb, struct tangox_wdt_device, restart);
+
+	writel(1, dev->base + WD_COUNTER);
+
+	return NOTIFY_DONE;
+}
+
+static int tangox_wdt_probe(struct platform_device *pdev)
+{
+	struct tangox_wdt_device *dev;
+	struct resource *res;
+	u32 config;
+	int err;
+
+	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	dev->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dev->base))
+		return PTR_ERR(dev->base);
+
+	dev->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(dev->clk))
+		return PTR_ERR(dev->clk);
+
+	err = clk_prepare_enable(dev->clk);
+	if (err)
+		return err;
+
+	dev->clk_rate = clk_get_rate(dev->clk);
+
+	dev->wdt.parent = &pdev->dev;
+	dev->wdt.info = &tangox_wdt_info;
+	dev->wdt.ops = &tangox_wdt_ops;
+	dev->wdt.timeout = DEFAULT_TIMEOUT;
+	dev->wdt.min_timeout = 1;
+	dev->wdt.max_timeout = (U32_MAX - 1) / dev->clk_rate;
+
+	watchdog_init_timeout(&dev->wdt, timeout, &pdev->dev);
+	watchdog_set_nowayout(&dev->wdt, nowayout);
+	watchdog_set_drvdata(&dev->wdt, dev);
+
+	/*
+	 * Deactivate counter if disable bit is set to avoid
+	 * accidental reset.
+	 */
+	config = readl(dev->base + WD_CONFIG);
+	if (config & WD_CONFIG_DISABLE)
+		writel(0, dev->base + WD_COUNTER);
+
+	writel(WD_CONFIG_XTAL_IN, dev->base + WD_CONFIG);
+
+	/*
+	 * Mark as active and restart with configured timeout if
+	 * already running.
+	 */
+	if (readl(dev->base + WD_COUNTER)) {
+		set_bit(WDOG_ACTIVE, &dev->wdt.status);
+		tangox_wdt_start(&dev->wdt);
+	}
+
+	err = watchdog_register_device(&dev->wdt);
+	if (err) {
+		clk_disable_unprepare(dev->clk);
+		return err;
+	}
+
+	platform_set_drvdata(pdev, dev);
+
+	dev->restart.notifier_call = tangox_wdt_restart;
+	dev->restart.priority = 128;
+	err = register_restart_handler(&dev->restart);
+	if (err)
+		dev_warn(&pdev->dev, "failed to register restart handler\n");
+
+	dev_info(&pdev->dev, "SMP86xx/SMP87xx watchdog registered\n");
+
+	return 0;
+}
+
+static int tangox_wdt_remove(struct platform_device *pdev)
+{
+	struct tangox_wdt_device *dev = platform_get_drvdata(pdev);
+
+	tangox_wdt_stop(&dev->wdt);
+	clk_disable_unprepare(dev->clk);
+
+	unregister_restart_handler(&dev->restart);
+	watchdog_unregister_device(&dev->wdt);
+
+	return 0;
+}
+
+static const struct of_device_id tangox_wdt_dt_ids[] = {
+	{ .compatible = "sigma,smp8642-wdt" },
+	{ .compatible = "sigma,smp8759-wdt" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tangox_wdt_dt_ids);
+
+static struct platform_driver tangox_wdt_driver = {
+	.probe	= tangox_wdt_probe,
+	.remove	= tangox_wdt_remove,
+	.driver	= {
+		.name		= "tangox-wdt",
+		.of_match_table	= tangox_wdt_dt_ids,
+	},
+};
+
+module_platform_driver(tangox_wdt_driver);
+
+MODULE_AUTHOR("Mans Rullgard <mans@mansr.com>");
+MODULE_DESCRIPTION("SMP86xx/SMP87xx Watchdog driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/ts4800_wdt.c b/drivers/watchdog/ts4800_wdt.c
new file mode 100644
index 0000000..2b8de86
--- /dev/null
+++ b/drivers/watchdog/ts4800_wdt.c
@@ -0,0 +1,215 @@
+/*
+ * Watchdog driver for TS-4800 based boards
+ *
+ * Copyright (c) 2015 - Savoir-faire Linux
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/watchdog.h>
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+	"Watchdog cannot be stopped once started (default="
+	__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+/* possible feed values */
+#define TS4800_WDT_FEED_2S       0x1
+#define TS4800_WDT_FEED_10S      0x2
+#define TS4800_WDT_DISABLE       0x3
+
+struct ts4800_wdt {
+	struct watchdog_device  wdd;
+	struct regmap           *regmap;
+	u32                     feed_offset;
+	u32                     feed_val;
+};
+
+/*
+ * TS-4800 supports the following timeout values:
+ *
+ *   value desc
+ *   ---------------------
+ *     0    feed for 338ms
+ *     1    feed for 2.706s
+ *     2    feed for 10.824s
+ *     3    disable watchdog
+ *
+ * Keep the regmap/timeout map ordered by timeout
+ */
+static const struct {
+	const int timeout;
+	const int regval;
+} ts4800_wdt_map[] = {
+	{ 2,  TS4800_WDT_FEED_2S },
+	{ 10, TS4800_WDT_FEED_10S },
+};
+
+#define MAX_TIMEOUT_INDEX       (ARRAY_SIZE(ts4800_wdt_map) - 1)
+
+static void ts4800_write_feed(struct ts4800_wdt *wdt, u32 val)
+{
+	regmap_write(wdt->regmap, wdt->feed_offset, val);
+}
+
+static int ts4800_wdt_start(struct watchdog_device *wdd)
+{
+	struct ts4800_wdt *wdt = watchdog_get_drvdata(wdd);
+
+	ts4800_write_feed(wdt, wdt->feed_val);
+	return 0;
+}
+
+static int ts4800_wdt_stop(struct watchdog_device *wdd)
+{
+	struct ts4800_wdt *wdt = watchdog_get_drvdata(wdd);
+
+	ts4800_write_feed(wdt, TS4800_WDT_DISABLE);
+	return 0;
+}
+
+static int ts4800_wdt_set_timeout(struct watchdog_device *wdd,
+				  unsigned int timeout)
+{
+	struct ts4800_wdt *wdt = watchdog_get_drvdata(wdd);
+	int i;
+
+	for (i = 0; i < MAX_TIMEOUT_INDEX; i++) {
+		if (ts4800_wdt_map[i].timeout >= timeout)
+			break;
+	}
+
+	wdd->timeout = ts4800_wdt_map[i].timeout;
+	wdt->feed_val = ts4800_wdt_map[i].regval;
+
+	return 0;
+}
+
+static const struct watchdog_ops ts4800_wdt_ops = {
+	.owner = THIS_MODULE,
+	.start = ts4800_wdt_start,
+	.stop = ts4800_wdt_stop,
+	.set_timeout = ts4800_wdt_set_timeout,
+};
+
+static const struct watchdog_info ts4800_wdt_info = {
+	.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+	.identity = "TS-4800 Watchdog",
+};
+
+static int ts4800_wdt_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *syscon_np;
+	struct watchdog_device *wdd;
+	struct ts4800_wdt *wdt;
+	u32 reg;
+	int ret;
+
+	syscon_np = of_parse_phandle(np, "syscon", 0);
+	if (!syscon_np) {
+		dev_err(&pdev->dev, "no syscon property\n");
+		return -ENODEV;
+	}
+
+	ret = of_property_read_u32_index(np, "syscon", 1, &reg);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "no offset in syscon\n");
+		return ret;
+	}
+
+	/* allocate memory for watchdog struct */
+	wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+	if (!wdt)
+		return -ENOMEM;
+
+	/* set regmap and offset to know where to write */
+	wdt->feed_offset = reg;
+	wdt->regmap = syscon_node_to_regmap(syscon_np);
+	if (IS_ERR(wdt->regmap)) {
+		dev_err(&pdev->dev, "cannot get parent's regmap\n");
+		return PTR_ERR(wdt->regmap);
+	}
+
+	/* Initialize struct watchdog_device */
+	wdd = &wdt->wdd;
+	wdd->parent = &pdev->dev;
+	wdd->info = &ts4800_wdt_info;
+	wdd->ops = &ts4800_wdt_ops;
+	wdd->min_timeout = ts4800_wdt_map[0].timeout;
+	wdd->max_timeout = ts4800_wdt_map[MAX_TIMEOUT_INDEX].timeout;
+
+	watchdog_set_drvdata(wdd, wdt);
+	watchdog_set_nowayout(wdd, nowayout);
+	watchdog_init_timeout(wdd, 0, &pdev->dev);
+
+	/*
+	 * As this watchdog supports only a few values, ts4800_wdt_set_timeout
+	 * must be called to initialize timeout and feed_val with valid values.
+	 * Default to maximum timeout if none, or an invalid one, is provided in
+	 * device tree.
+	 */
+	if (!wdd->timeout)
+		wdd->timeout = wdd->max_timeout;
+	ts4800_wdt_set_timeout(wdd, wdd->timeout);
+
+	/*
+	 * The feed register is write-only, so it is not possible to determine
+	 * watchdog's state. Disable it to be in a known state.
+	 */
+	ts4800_wdt_stop(wdd);
+
+	ret = watchdog_register_device(wdd);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"failed to register watchdog device\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, wdt);
+
+	dev_info(&pdev->dev,
+		 "initialized (timeout = %d sec, nowayout = %d)\n",
+		 wdd->timeout, nowayout);
+
+	return 0;
+}
+
+static int ts4800_wdt_remove(struct platform_device *pdev)
+{
+	struct ts4800_wdt *wdt = platform_get_drvdata(pdev);
+
+	watchdog_unregister_device(&wdt->wdd);
+
+	return 0;
+}
+
+static const struct of_device_id ts4800_wdt_of_match[] = {
+	{ .compatible = "technologic,ts4800-wdt", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ts4800_wdt_of_match);
+
+static struct platform_driver ts4800_wdt_driver = {
+	.probe		= ts4800_wdt_probe,
+	.remove		= ts4800_wdt_remove,
+	.driver		= {
+		.name	= "ts4800_wdt",
+		.of_match_table = ts4800_wdt_of_match,
+	},
+};
+
+module_platform_driver(ts4800_wdt_driver);
+
+MODULE_AUTHOR("Damien Riegel <damien.riegel@savoirfairelinux.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ts4800_wdt");
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
index 5824e25..cab14bc 100644
--- a/drivers/watchdog/w83627hf_wdt.c
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -36,8 +36,6 @@
 #include <linux/types.h>
 #include <linux/watchdog.h>
 #include <linux/ioport.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/io.h>
 
@@ -288,18 +286,6 @@
 }
 
 /*
- *	Notifier for system down
- */
-static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
-	void *unused)
-{
-	if (code == SYS_DOWN || code == SYS_HALT)
-		wdt_set_time(0);	/* Turn the WDT off */
-
-	return NOTIFY_DONE;
-}
-
-/*
  *	Kernel Interfaces
  */
 
@@ -329,10 +315,6 @@
  *	turn the timebomb registers off.
  */
 
-static struct notifier_block wdt_notifier = {
-	.notifier_call = wdt_notify_sys,
-};
-
 static int wdt_find(int addr)
 {
 	u8 val;
@@ -456,6 +438,7 @@
 
 	watchdog_init_timeout(&wdt_dev, timeout, NULL);
 	watchdog_set_nowayout(&wdt_dev, nowayout);
+	watchdog_stop_on_reboot(&wdt_dev);
 
 	ret = w83627hf_init(&wdt_dev, chip);
 	if (ret) {
@@ -463,30 +446,19 @@
 		return ret;
 	}
 
-	ret = register_reboot_notifier(&wdt_notifier);
-	if (ret != 0) {
-		pr_err("cannot register reboot notifier (err=%d)\n", ret);
-		return ret;
-	}
-
 	ret = watchdog_register_device(&wdt_dev);
 	if (ret)
-		goto unreg_reboot;
+		return ret;
 
 	pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
 		wdt_dev.timeout, nowayout);
 
 	return ret;
-
-unreg_reboot:
-	unregister_reboot_notifier(&wdt_notifier);
-	return ret;
 }
 
 static void __exit wdt_exit(void)
 {
 	watchdog_unregister_device(&wdt_dev);
-	unregister_reboot_notifier(&wdt_notifier);
 }
 
 module_init(wdt_init);
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
index 873f139..e600fd9 100644
--- a/drivers/watchdog/watchdog_core.c
+++ b/drivers/watchdog/watchdog_core.c
@@ -32,6 +32,7 @@
 #include <linux/types.h>	/* For standard types */
 #include <linux/errno.h>	/* For the -ENODEV/... values */
 #include <linux/kernel.h>	/* For printk/panic/... */
+#include <linux/reboot.h>	/* For restart handler */
 #include <linux/watchdog.h>	/* For watchdog specific items */
 #include <linux/init.h>		/* For __init/__exit/... */
 #include <linux/idr.h>		/* For ida_* macros */
@@ -41,7 +42,6 @@
 #include "watchdog_core.h"	/* For watchdog_dev_register/... */
 
 static DEFINE_IDA(watchdog_ida);
-static struct class *watchdog_class;
 
 /*
  * Deferred Registration infrastructure.
@@ -137,9 +137,63 @@
 }
 EXPORT_SYMBOL_GPL(watchdog_init_timeout);
 
+static int watchdog_reboot_notifier(struct notifier_block *nb,
+				    unsigned long code, void *data)
+{
+	struct watchdog_device *wdd = container_of(nb, struct watchdog_device,
+						   reboot_nb);
+
+	if (code == SYS_DOWN || code == SYS_HALT) {
+		if (watchdog_active(wdd)) {
+			int ret;
+
+			ret = wdd->ops->stop(wdd);
+			if (ret)
+				return NOTIFY_BAD;
+		}
+	}
+
+	return NOTIFY_DONE;
+}
+
+static int watchdog_restart_notifier(struct notifier_block *nb,
+				     unsigned long action, void *data)
+{
+	struct watchdog_device *wdd = container_of(nb, struct watchdog_device,
+						   restart_nb);
+
+	int ret;
+
+	ret = wdd->ops->restart(wdd);
+	if (ret)
+		return NOTIFY_BAD;
+
+	return NOTIFY_DONE;
+}
+
+/**
+ * watchdog_set_restart_priority - Change priority of restart handler
+ * @wdd: watchdog device
+ * @priority: priority of the restart handler, should follow these guidelines:
+ *   0:   use watchdog's restart function as last resort, has limited restart
+ *        capabilies
+ *   128: default restart handler, use if no other handler is expected to be
+ *        available and/or if restart is sufficient to restart the entire system
+ *   255: preempt all other handlers
+ *
+ * If a wdd->ops->restart function is provided when watchdog_register_device is
+ * called, it will be registered as a restart handler with the priority given
+ * here.
+ */
+void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority)
+{
+	wdd->restart_nb.priority = priority;
+}
+EXPORT_SYMBOL_GPL(watchdog_set_restart_priority);
+
 static int __watchdog_register_device(struct watchdog_device *wdd)
 {
-	int ret, id = -1, devno;
+	int ret, id = -1;
 
 	if (wdd == NULL || wdd->info == NULL || wdd->ops == NULL)
 		return -EINVAL;
@@ -156,8 +210,6 @@
 	 * corrupted in a later stage then we expect a kernel panic!
 	 */
 
-	mutex_init(&wdd->lock);
-
 	/* Use alias for watchdog id if possible */
 	if (wdd->parent) {
 		ret = of_alias_get_id(wdd->parent->of_node, "watchdog");
@@ -192,14 +244,26 @@
 		}
 	}
 
-	devno = wdd->cdev.dev;
-	wdd->dev = device_create(watchdog_class, wdd->parent, devno,
-					NULL, "watchdog%d", wdd->id);
-	if (IS_ERR(wdd->dev)) {
-		watchdog_dev_unregister(wdd);
-		ida_simple_remove(&watchdog_ida, id);
-		ret = PTR_ERR(wdd->dev);
-		return ret;
+	if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status)) {
+		wdd->reboot_nb.notifier_call = watchdog_reboot_notifier;
+
+		ret = register_reboot_notifier(&wdd->reboot_nb);
+		if (ret) {
+			pr_err("watchdog%d: Cannot register reboot notifier (%d)\n",
+			       wdd->id, ret);
+			watchdog_dev_unregister(wdd);
+			ida_simple_remove(&watchdog_ida, wdd->id);
+			return ret;
+		}
+	}
+
+	if (wdd->ops->restart) {
+		wdd->restart_nb.notifier_call = watchdog_restart_notifier;
+
+		ret = register_restart_handler(&wdd->restart_nb);
+		if (ret)
+			pr_warn("watchog%d: Cannot register restart handler (%d)\n",
+				wdd->id, ret);
 	}
 
 	return 0;
@@ -232,19 +296,17 @@
 
 static void __watchdog_unregister_device(struct watchdog_device *wdd)
 {
-	int ret;
-	int devno;
-
 	if (wdd == NULL)
 		return;
 
-	devno = wdd->cdev.dev;
-	ret = watchdog_dev_unregister(wdd);
-	if (ret)
-		pr_err("error unregistering /dev/watchdog (err=%d)\n", ret);
-	device_destroy(watchdog_class, devno);
+	if (wdd->ops->restart)
+		unregister_restart_handler(&wdd->restart_nb);
+
+	if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status))
+		unregister_reboot_notifier(&wdd->reboot_nb);
+
+	watchdog_dev_unregister(wdd);
 	ida_simple_remove(&watchdog_ida, wdd->id);
-	wdd->dev = NULL;
 }
 
 /**
@@ -287,17 +349,9 @@
 {
 	int err;
 
-	watchdog_class = class_create(THIS_MODULE, "watchdog");
-	if (IS_ERR(watchdog_class)) {
-		pr_err("couldn't create class\n");
-		return PTR_ERR(watchdog_class);
-	}
-
 	err = watchdog_dev_init();
-	if (err < 0) {
-		class_destroy(watchdog_class);
+	if (err < 0)
 		return err;
-	}
 
 	watchdog_deferred_registration();
 	return 0;
@@ -306,7 +360,6 @@
 static void __exit watchdog_exit(void)
 {
 	watchdog_dev_exit();
-	class_destroy(watchdog_class);
 	ida_destroy(&watchdog_ida);
 }
 
diff --git a/drivers/watchdog/watchdog_core.h b/drivers/watchdog/watchdog_core.h
index 6c95141..86ff962 100644
--- a/drivers/watchdog/watchdog_core.h
+++ b/drivers/watchdog/watchdog_core.h
@@ -32,6 +32,6 @@
  *	Functions/procedures to be called by the core
  */
 extern int watchdog_dev_register(struct watchdog_device *);
-extern int watchdog_dev_unregister(struct watchdog_device *);
+extern void watchdog_dev_unregister(struct watchdog_device *);
 extern int __init watchdog_dev_init(void);
 extern void __exit watchdog_dev_exit(void);
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 56a649e..ba2ecce 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -32,27 +32,51 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/module.h>	/* For module stuff/... */
-#include <linux/types.h>	/* For standard types (like size_t) */
+#include <linux/cdev.h>		/* For character device */
 #include <linux/errno.h>	/* For the -ENODEV/... values */
-#include <linux/kernel.h>	/* For printk/panic/... */
 #include <linux/fs.h>		/* For file operations */
-#include <linux/watchdog.h>	/* For watchdog specific items */
-#include <linux/miscdevice.h>	/* For handling misc devices */
 #include <linux/init.h>		/* For __init/__exit/... */
+#include <linux/kernel.h>	/* For printk/panic/... */
+#include <linux/kref.h>		/* For data references */
+#include <linux/miscdevice.h>	/* For handling misc devices */
+#include <linux/module.h>	/* For module stuff/... */
+#include <linux/mutex.h>	/* For mutexes */
+#include <linux/slab.h>		/* For memory functions */
+#include <linux/types.h>	/* For standard types (like size_t) */
+#include <linux/watchdog.h>	/* For watchdog specific items */
 #include <linux/uaccess.h>	/* For copy_to_user/put_user/... */
 
 #include "watchdog_core.h"
 
+/*
+ * struct watchdog_core_data - watchdog core internal data
+ * @kref:	Reference count.
+ * @cdev:	The watchdog's Character device.
+ * @wdd:	Pointer to watchdog device.
+ * @lock:	Lock for watchdog core.
+ * @status:	Watchdog core internal status bits.
+ */
+struct watchdog_core_data {
+	struct kref kref;
+	struct cdev cdev;
+	struct watchdog_device *wdd;
+	struct mutex lock;
+	unsigned long status;		/* Internal status bits */
+#define _WDOG_DEV_OPEN		0	/* Opened ? */
+#define _WDOG_ALLOW_RELEASE	1	/* Did we receive the magic char ? */
+};
+
 /* the dev_t structure to store the dynamically allocated watchdog devices */
 static dev_t watchdog_devt;
-/* the watchdog device behind /dev/watchdog */
-static struct watchdog_device *old_wdd;
+/* Reference to watchdog device behind /dev/watchdog */
+static struct watchdog_core_data *old_wd_data;
 
 /*
  *	watchdog_ping: ping the watchdog.
  *	@wdd: the watchdog device to ping
  *
+ *	The caller must hold wd_data->lock.
+ *
  *	If the watchdog has no own ping operation then it needs to be
  *	restarted via the start operation. This wrapper function does
  *	exactly that.
@@ -61,25 +85,16 @@
 
 static int watchdog_ping(struct watchdog_device *wdd)
 {
-	int err = 0;
-
-	mutex_lock(&wdd->lock);
-
-	if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
-		err = -ENODEV;
-		goto out_ping;
-	}
+	int err;
 
 	if (!watchdog_active(wdd))
-		goto out_ping;
+		return 0;
 
 	if (wdd->ops->ping)
 		err = wdd->ops->ping(wdd);	/* ping the watchdog */
 	else
 		err = wdd->ops->start(wdd);	/* restart watchdog */
 
-out_ping:
-	mutex_unlock(&wdd->lock);
 	return err;
 }
 
@@ -87,6 +102,8 @@
  *	watchdog_start: wrapper to start the watchdog.
  *	@wdd: the watchdog device to start
  *
+ *	The caller must hold wd_data->lock.
+ *
  *	Start the watchdog if it is not active and mark it active.
  *	This function returns zero on success or a negative errno code for
  *	failure.
@@ -94,24 +111,15 @@
 
 static int watchdog_start(struct watchdog_device *wdd)
 {
-	int err = 0;
-
-	mutex_lock(&wdd->lock);
-
-	if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
-		err = -ENODEV;
-		goto out_start;
-	}
+	int err;
 
 	if (watchdog_active(wdd))
-		goto out_start;
+		return 0;
 
 	err = wdd->ops->start(wdd);
 	if (err == 0)
 		set_bit(WDOG_ACTIVE, &wdd->status);
 
-out_start:
-	mutex_unlock(&wdd->lock);
 	return err;
 }
 
@@ -119,6 +127,8 @@
  *	watchdog_stop: wrapper to stop the watchdog.
  *	@wdd: the watchdog device to stop
  *
+ *	The caller must hold wd_data->lock.
+ *
  *	Stop the watchdog if it is still active and unmark it active.
  *	This function returns zero on success or a negative errno code for
  *	failure.
@@ -127,93 +137,59 @@
 
 static int watchdog_stop(struct watchdog_device *wdd)
 {
-	int err = 0;
-
-	mutex_lock(&wdd->lock);
-
-	if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
-		err = -ENODEV;
-		goto out_stop;
-	}
+	int err;
 
 	if (!watchdog_active(wdd))
-		goto out_stop;
+		return 0;
 
 	if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) {
-		dev_info(wdd->dev, "nowayout prevents watchdog being stopped!\n");
-		err = -EBUSY;
-		goto out_stop;
+		pr_info("watchdog%d: nowayout prevents watchdog being stopped!\n",
+			wdd->id);
+		return -EBUSY;
 	}
 
 	err = wdd->ops->stop(wdd);
 	if (err == 0)
 		clear_bit(WDOG_ACTIVE, &wdd->status);
 
-out_stop:
-	mutex_unlock(&wdd->lock);
 	return err;
 }
 
 /*
  *	watchdog_get_status: wrapper to get the watchdog status
  *	@wdd: the watchdog device to get the status from
- *	@status: the status of the watchdog device
+ *
+ *	The caller must hold wd_data->lock.
  *
  *	Get the watchdog's status flags.
  */
 
-static int watchdog_get_status(struct watchdog_device *wdd,
-							unsigned int *status)
+static unsigned int watchdog_get_status(struct watchdog_device *wdd)
 {
-	int err = 0;
-
-	*status = 0;
 	if (!wdd->ops->status)
-		return -EOPNOTSUPP;
+		return 0;
 
-	mutex_lock(&wdd->lock);
-
-	if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
-		err = -ENODEV;
-		goto out_status;
-	}
-
-	*status = wdd->ops->status(wdd);
-
-out_status:
-	mutex_unlock(&wdd->lock);
-	return err;
+	return wdd->ops->status(wdd);
 }
 
 /*
  *	watchdog_set_timeout: set the watchdog timer timeout
  *	@wdd: the watchdog device to set the timeout for
  *	@timeout: timeout to set in seconds
+ *
+ *	The caller must hold wd_data->lock.
  */
 
 static int watchdog_set_timeout(struct watchdog_device *wdd,
 							unsigned int timeout)
 {
-	int err;
-
 	if (!wdd->ops->set_timeout || !(wdd->info->options & WDIOF_SETTIMEOUT))
 		return -EOPNOTSUPP;
 
 	if (watchdog_timeout_invalid(wdd, timeout))
 		return -EINVAL;
 
-	mutex_lock(&wdd->lock);
-
-	if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
-		err = -ENODEV;
-		goto out_timeout;
-	}
-
-	err = wdd->ops->set_timeout(wdd, timeout);
-
-out_timeout:
-	mutex_unlock(&wdd->lock);
-	return err;
+	return wdd->ops->set_timeout(wdd, timeout);
 }
 
 /*
@@ -221,59 +197,156 @@
  *	@wdd: the watchdog device to get the remaining time from
  *	@timeleft: the time that's left
  *
+ *	The caller must hold wd_data->lock.
+ *
  *	Get the time before a watchdog will reboot (if not pinged).
  */
 
 static int watchdog_get_timeleft(struct watchdog_device *wdd,
 							unsigned int *timeleft)
 {
-	int err = 0;
-
 	*timeleft = 0;
+
 	if (!wdd->ops->get_timeleft)
 		return -EOPNOTSUPP;
 
-	mutex_lock(&wdd->lock);
-
-	if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
-		err = -ENODEV;
-		goto out_timeleft;
-	}
-
 	*timeleft = wdd->ops->get_timeleft(wdd);
 
-out_timeleft:
-	mutex_unlock(&wdd->lock);
-	return err;
+	return 0;
 }
 
+#ifdef CONFIG_WATCHDOG_SYSFS
+static ssize_t nowayout_show(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", !!test_bit(WDOG_NO_WAY_OUT, &wdd->status));
+}
+static DEVICE_ATTR_RO(nowayout);
+
+static ssize_t status_show(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct watchdog_device *wdd = dev_get_drvdata(dev);
+	struct watchdog_core_data *wd_data = wdd->wd_data;
+	unsigned int status;
+
+	mutex_lock(&wd_data->lock);
+	status = watchdog_get_status(wdd);
+	mutex_unlock(&wd_data->lock);
+
+	return sprintf(buf, "%u\n", status);
+}
+static DEVICE_ATTR_RO(status);
+
+static ssize_t bootstatus_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", wdd->bootstatus);
+}
+static DEVICE_ATTR_RO(bootstatus);
+
+static ssize_t timeleft_show(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct watchdog_device *wdd = dev_get_drvdata(dev);
+	struct watchdog_core_data *wd_data = wdd->wd_data;
+	ssize_t status;
+	unsigned int val;
+
+	mutex_lock(&wd_data->lock);
+	status = watchdog_get_timeleft(wdd, &val);
+	mutex_unlock(&wd_data->lock);
+	if (!status)
+		status = sprintf(buf, "%u\n", val);
+
+	return status;
+}
+static DEVICE_ATTR_RO(timeleft);
+
+static ssize_t timeout_show(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", wdd->timeout);
+}
+static DEVICE_ATTR_RO(timeout);
+
+static ssize_t identity_show(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", wdd->info->identity);
+}
+static DEVICE_ATTR_RO(identity);
+
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+	if (watchdog_active(wdd))
+		return sprintf(buf, "active\n");
+
+	return sprintf(buf, "inactive\n");
+}
+static DEVICE_ATTR_RO(state);
+
+static umode_t wdt_is_visible(struct kobject *kobj, struct attribute *attr,
+				int n)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct watchdog_device *wdd = dev_get_drvdata(dev);
+	umode_t mode = attr->mode;
+
+	if (attr == &dev_attr_status.attr && !wdd->ops->status)
+		mode = 0;
+	else if (attr == &dev_attr_timeleft.attr && !wdd->ops->get_timeleft)
+		mode = 0;
+
+	return mode;
+}
+static struct attribute *wdt_attrs[] = {
+	&dev_attr_state.attr,
+	&dev_attr_identity.attr,
+	&dev_attr_timeout.attr,
+	&dev_attr_timeleft.attr,
+	&dev_attr_bootstatus.attr,
+	&dev_attr_status.attr,
+	&dev_attr_nowayout.attr,
+	NULL,
+};
+
+static const struct attribute_group wdt_group = {
+	.attrs = wdt_attrs,
+	.is_visible = wdt_is_visible,
+};
+__ATTRIBUTE_GROUPS(wdt);
+#else
+#define wdt_groups	NULL
+#endif
+
 /*
  *	watchdog_ioctl_op: call the watchdog drivers ioctl op if defined
  *	@wdd: the watchdog device to do the ioctl on
  *	@cmd: watchdog command
  *	@arg: argument pointer
+ *
+ *	The caller must hold wd_data->lock.
  */
 
 static int watchdog_ioctl_op(struct watchdog_device *wdd, unsigned int cmd,
 							unsigned long arg)
 {
-	int err;
-
 	if (!wdd->ops->ioctl)
 		return -ENOIOCTLCMD;
 
-	mutex_lock(&wdd->lock);
-
-	if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
-		err = -ENODEV;
-		goto out_ioctl;
-	}
-
-	err = wdd->ops->ioctl(wdd, cmd, arg);
-
-out_ioctl:
-	mutex_unlock(&wdd->lock);
-	return err;
+	return wdd->ops->ioctl(wdd, cmd, arg);
 }
 
 /*
@@ -291,10 +364,11 @@
 static ssize_t watchdog_write(struct file *file, const char __user *data,
 						size_t len, loff_t *ppos)
 {
-	struct watchdog_device *wdd = file->private_data;
+	struct watchdog_core_data *wd_data = file->private_data;
+	struct watchdog_device *wdd;
+	int err;
 	size_t i;
 	char c;
-	int err;
 
 	if (len == 0)
 		return 0;
@@ -303,18 +377,25 @@
 	 * Note: just in case someone wrote the magic character
 	 * five months ago...
 	 */
-	clear_bit(WDOG_ALLOW_RELEASE, &wdd->status);
+	clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status);
 
 	/* scan to see whether or not we got the magic character */
 	for (i = 0; i != len; i++) {
 		if (get_user(c, data + i))
 			return -EFAULT;
 		if (c == 'V')
-			set_bit(WDOG_ALLOW_RELEASE, &wdd->status);
+			set_bit(_WDOG_ALLOW_RELEASE, &wd_data->status);
 	}
 
 	/* someone wrote to us, so we send the watchdog a keepalive ping */
-	err = watchdog_ping(wdd);
+
+	err = -ENODEV;
+	mutex_lock(&wd_data->lock);
+	wdd = wd_data->wdd;
+	if (wdd)
+		err = watchdog_ping(wdd);
+	mutex_unlock(&wd_data->lock);
+
 	if (err < 0)
 		return err;
 
@@ -334,71 +415,94 @@
 static long watchdog_ioctl(struct file *file, unsigned int cmd,
 							unsigned long arg)
 {
-	struct watchdog_device *wdd = file->private_data;
+	struct watchdog_core_data *wd_data = file->private_data;
 	void __user *argp = (void __user *)arg;
+	struct watchdog_device *wdd;
 	int __user *p = argp;
 	unsigned int val;
 	int err;
 
+	mutex_lock(&wd_data->lock);
+
+	wdd = wd_data->wdd;
+	if (!wdd) {
+		err = -ENODEV;
+		goto out_ioctl;
+	}
+
 	err = watchdog_ioctl_op(wdd, cmd, arg);
 	if (err != -ENOIOCTLCMD)
-		return err;
+		goto out_ioctl;
 
 	switch (cmd) {
 	case WDIOC_GETSUPPORT:
-		return copy_to_user(argp, wdd->info,
+		err = copy_to_user(argp, wdd->info,
 			sizeof(struct watchdog_info)) ? -EFAULT : 0;
+		break;
 	case WDIOC_GETSTATUS:
-		err = watchdog_get_status(wdd, &val);
-		if (err == -ENODEV)
-			return err;
-		return put_user(val, p);
+		val = watchdog_get_status(wdd);
+		err = put_user(val, p);
+		break;
 	case WDIOC_GETBOOTSTATUS:
-		return put_user(wdd->bootstatus, p);
+		err = put_user(wdd->bootstatus, p);
+		break;
 	case WDIOC_SETOPTIONS:
-		if (get_user(val, p))
-			return -EFAULT;
+		if (get_user(val, p)) {
+			err = -EFAULT;
+			break;
+		}
 		if (val & WDIOS_DISABLECARD) {
 			err = watchdog_stop(wdd);
 			if (err < 0)
-				return err;
+				break;
 		}
-		if (val & WDIOS_ENABLECARD) {
+		if (val & WDIOS_ENABLECARD)
 			err = watchdog_start(wdd);
-			if (err < 0)
-				return err;
-		}
-		return 0;
+		break;
 	case WDIOC_KEEPALIVE:
-		if (!(wdd->info->options & WDIOF_KEEPALIVEPING))
-			return -EOPNOTSUPP;
-		return watchdog_ping(wdd);
+		if (!(wdd->info->options & WDIOF_KEEPALIVEPING)) {
+			err = -EOPNOTSUPP;
+			break;
+		}
+		err = watchdog_ping(wdd);
+		break;
 	case WDIOC_SETTIMEOUT:
-		if (get_user(val, p))
-			return -EFAULT;
+		if (get_user(val, p)) {
+			err = -EFAULT;
+			break;
+		}
 		err = watchdog_set_timeout(wdd, val);
 		if (err < 0)
-			return err;
+			break;
 		/* If the watchdog is active then we send a keepalive ping
 		 * to make sure that the watchdog keep's running (and if
 		 * possible that it takes the new timeout) */
 		err = watchdog_ping(wdd);
 		if (err < 0)
-			return err;
+			break;
 		/* Fall */
 	case WDIOC_GETTIMEOUT:
 		/* timeout == 0 means that we don't know the timeout */
-		if (wdd->timeout == 0)
-			return -EOPNOTSUPP;
-		return put_user(wdd->timeout, p);
+		if (wdd->timeout == 0) {
+			err = -EOPNOTSUPP;
+			break;
+		}
+		err = put_user(wdd->timeout, p);
+		break;
 	case WDIOC_GETTIMELEFT:
 		err = watchdog_get_timeleft(wdd, &val);
-		if (err)
-			return err;
-		return put_user(val, p);
+		if (err < 0)
+			break;
+		err = put_user(val, p);
+		break;
 	default:
-		return -ENOTTY;
+		err = -ENOTTY;
+		break;
 	}
+
+out_ioctl:
+	mutex_unlock(&wd_data->lock);
+	return err;
 }
 
 /*
@@ -413,45 +517,59 @@
 
 static int watchdog_open(struct inode *inode, struct file *file)
 {
-	int err = -EBUSY;
+	struct watchdog_core_data *wd_data;
 	struct watchdog_device *wdd;
+	int err;
 
 	/* Get the corresponding watchdog device */
 	if (imajor(inode) == MISC_MAJOR)
-		wdd = old_wdd;
+		wd_data = old_wd_data;
 	else
-		wdd = container_of(inode->i_cdev, struct watchdog_device, cdev);
+		wd_data = container_of(inode->i_cdev, struct watchdog_core_data,
+				       cdev);
 
 	/* the watchdog is single open! */
-	if (test_and_set_bit(WDOG_DEV_OPEN, &wdd->status))
+	if (test_and_set_bit(_WDOG_DEV_OPEN, &wd_data->status))
 		return -EBUSY;
 
+	wdd = wd_data->wdd;
+
 	/*
 	 * If the /dev/watchdog device is open, we don't want the module
 	 * to be unloaded.
 	 */
-	if (!try_module_get(wdd->ops->owner))
-		goto out;
+	if (!try_module_get(wdd->ops->owner)) {
+		err = -EBUSY;
+		goto out_clear;
+	}
 
 	err = watchdog_start(wdd);
 	if (err < 0)
 		goto out_mod;
 
-	file->private_data = wdd;
+	file->private_data = wd_data;
 
-	if (wdd->ops->ref)
-		wdd->ops->ref(wdd);
+	kref_get(&wd_data->kref);
 
 	/* dev/watchdog is a virtual (and thus non-seekable) filesystem */
 	return nonseekable_open(inode, file);
 
 out_mod:
-	module_put(wdd->ops->owner);
-out:
-	clear_bit(WDOG_DEV_OPEN, &wdd->status);
+	module_put(wd_data->wdd->ops->owner);
+out_clear:
+	clear_bit(_WDOG_DEV_OPEN, &wd_data->status);
 	return err;
 }
 
+static void watchdog_core_data_release(struct kref *kref)
+{
+	struct watchdog_core_data *wd_data;
+
+	wd_data = container_of(kref, struct watchdog_core_data, kref);
+
+	kfree(wd_data);
+}
+
 /*
  *	watchdog_release: release the watchdog device.
  *	@inode: inode of device
@@ -464,9 +582,16 @@
 
 static int watchdog_release(struct inode *inode, struct file *file)
 {
-	struct watchdog_device *wdd = file->private_data;
+	struct watchdog_core_data *wd_data = file->private_data;
+	struct watchdog_device *wdd;
 	int err = -EBUSY;
 
+	mutex_lock(&wd_data->lock);
+
+	wdd = wd_data->wdd;
+	if (!wdd)
+		goto done;
+
 	/*
 	 * We only stop the watchdog if we received the magic character
 	 * or if WDIOF_MAGICCLOSE is not set. If nowayout was set then
@@ -474,29 +599,24 @@
 	 */
 	if (!test_bit(WDOG_ACTIVE, &wdd->status))
 		err = 0;
-	else if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) ||
+	else if (test_and_clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status) ||
 		 !(wdd->info->options & WDIOF_MAGICCLOSE))
 		err = watchdog_stop(wdd);
 
 	/* If the watchdog was not stopped, send a keepalive ping */
 	if (err < 0) {
-		mutex_lock(&wdd->lock);
-		if (!test_bit(WDOG_UNREGISTERED, &wdd->status))
-			dev_crit(wdd->dev, "watchdog did not stop!\n");
-		mutex_unlock(&wdd->lock);
+		pr_crit("watchdog%d: watchdog did not stop!\n", wdd->id);
 		watchdog_ping(wdd);
 	}
 
-	/* Allow the owner module to be unloaded again */
-	module_put(wdd->ops->owner);
-
 	/* make sure that /dev/watchdog can be re-opened */
-	clear_bit(WDOG_DEV_OPEN, &wdd->status);
+	clear_bit(_WDOG_DEV_OPEN, &wd_data->status);
 
-	/* Note wdd may be gone after this, do not use after this! */
-	if (wdd->ops->unref)
-		wdd->ops->unref(wdd);
-
+done:
+	mutex_unlock(&wd_data->lock);
+	/* Allow the owner module to be unloaded again */
+	module_put(wd_data->cdev.owner);
+	kref_put(&wd_data->kref, watchdog_core_data_release);
 	return 0;
 }
 
@@ -515,6 +635,96 @@
 };
 
 /*
+ *	watchdog_cdev_register: register watchdog character device
+ *	@wdd: watchdog device
+ *	@devno: character device number
+ *
+ *	Register a watchdog character device including handling the legacy
+ *	/dev/watchdog node. /dev/watchdog is actually a miscdevice and
+ *	thus we set it up like that.
+ */
+
+static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno)
+{
+	struct watchdog_core_data *wd_data;
+	int err;
+
+	wd_data = kzalloc(sizeof(struct watchdog_core_data), GFP_KERNEL);
+	if (!wd_data)
+		return -ENOMEM;
+	kref_init(&wd_data->kref);
+	mutex_init(&wd_data->lock);
+
+	wd_data->wdd = wdd;
+	wdd->wd_data = wd_data;
+
+	if (wdd->id == 0) {
+		old_wd_data = wd_data;
+		watchdog_miscdev.parent = wdd->parent;
+		err = misc_register(&watchdog_miscdev);
+		if (err != 0) {
+			pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n",
+				wdd->info->identity, WATCHDOG_MINOR, err);
+			if (err == -EBUSY)
+				pr_err("%s: a legacy watchdog module is probably present.\n",
+					wdd->info->identity);
+			old_wd_data = NULL;
+			kfree(wd_data);
+			return err;
+		}
+	}
+
+	/* Fill in the data structures */
+	cdev_init(&wd_data->cdev, &watchdog_fops);
+	wd_data->cdev.owner = wdd->ops->owner;
+
+	/* Add the device */
+	err = cdev_add(&wd_data->cdev, devno, 1);
+	if (err) {
+		pr_err("watchdog%d unable to add device %d:%d\n",
+			wdd->id,  MAJOR(watchdog_devt), wdd->id);
+		if (wdd->id == 0) {
+			misc_deregister(&watchdog_miscdev);
+			old_wd_data = NULL;
+			kref_put(&wd_data->kref, watchdog_core_data_release);
+		}
+	}
+	return err;
+}
+
+/*
+ *	watchdog_cdev_unregister: unregister watchdog character device
+ *	@watchdog: watchdog device
+ *
+ *	Unregister watchdog character device and if needed the legacy
+ *	/dev/watchdog device.
+ */
+
+static void watchdog_cdev_unregister(struct watchdog_device *wdd)
+{
+	struct watchdog_core_data *wd_data = wdd->wd_data;
+
+	cdev_del(&wd_data->cdev);
+	if (wdd->id == 0) {
+		misc_deregister(&watchdog_miscdev);
+		old_wd_data = NULL;
+	}
+
+	mutex_lock(&wd_data->lock);
+	wd_data->wdd = NULL;
+	wdd->wd_data = NULL;
+	mutex_unlock(&wd_data->lock);
+
+	kref_put(&wd_data->kref, watchdog_core_data_release);
+}
+
+static struct class watchdog_class = {
+	.name =		"watchdog",
+	.owner =	THIS_MODULE,
+	.dev_groups =	wdt_groups,
+};
+
+/*
  *	watchdog_dev_register: register a watchdog device
  *	@wdd: watchdog device
  *
@@ -525,60 +735,39 @@
 
 int watchdog_dev_register(struct watchdog_device *wdd)
 {
-	int err, devno;
+	struct device *dev;
+	dev_t devno;
+	int ret;
 
-	if (wdd->id == 0) {
-		old_wdd = wdd;
-		watchdog_miscdev.parent = wdd->parent;
-		err = misc_register(&watchdog_miscdev);
-		if (err != 0) {
-			pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n",
-				wdd->info->identity, WATCHDOG_MINOR, err);
-			if (err == -EBUSY)
-				pr_err("%s: a legacy watchdog module is probably present.\n",
-					wdd->info->identity);
-			old_wdd = NULL;
-			return err;
-		}
-	}
-
-	/* Fill in the data structures */
 	devno = MKDEV(MAJOR(watchdog_devt), wdd->id);
-	cdev_init(&wdd->cdev, &watchdog_fops);
-	wdd->cdev.owner = wdd->ops->owner;
 
-	/* Add the device */
-	err  = cdev_add(&wdd->cdev, devno, 1);
-	if (err) {
-		pr_err("watchdog%d unable to add device %d:%d\n",
-			wdd->id,  MAJOR(watchdog_devt), wdd->id);
-		if (wdd->id == 0) {
-			misc_deregister(&watchdog_miscdev);
-			old_wdd = NULL;
-		}
+	ret = watchdog_cdev_register(wdd, devno);
+	if (ret)
+		return ret;
+
+	dev = device_create_with_groups(&watchdog_class, wdd->parent,
+					devno, wdd, wdd->groups,
+					"watchdog%d", wdd->id);
+	if (IS_ERR(dev)) {
+		watchdog_cdev_unregister(wdd);
+		return PTR_ERR(dev);
 	}
-	return err;
+
+	return ret;
 }
 
 /*
  *	watchdog_dev_unregister: unregister a watchdog device
  *	@watchdog: watchdog device
  *
- *	Unregister the watchdog and if needed the legacy /dev/watchdog device.
+ *	Unregister watchdog device and if needed the legacy
+ *	/dev/watchdog device.
  */
 
-int watchdog_dev_unregister(struct watchdog_device *wdd)
+void watchdog_dev_unregister(struct watchdog_device *wdd)
 {
-	mutex_lock(&wdd->lock);
-	set_bit(WDOG_UNREGISTERED, &wdd->status);
-	mutex_unlock(&wdd->lock);
-
-	cdev_del(&wdd->cdev);
-	if (wdd->id == 0) {
-		misc_deregister(&watchdog_miscdev);
-		old_wdd = NULL;
-	}
-	return 0;
+	device_destroy(&watchdog_class, wdd->wd_data->cdev.dev);
+	watchdog_cdev_unregister(wdd);
 }
 
 /*
@@ -589,10 +778,22 @@
 
 int __init watchdog_dev_init(void)
 {
-	int err = alloc_chrdev_region(&watchdog_devt, 0, MAX_DOGS, "watchdog");
-	if (err < 0)
+	int err;
+
+	err = class_register(&watchdog_class);
+	if (err < 0) {
+		pr_err("couldn't register class\n");
+		return err;
+	}
+
+	err = alloc_chrdev_region(&watchdog_devt, 0, MAX_DOGS, "watchdog");
+	if (err < 0) {
 		pr_err("watchdog: unable to allocate char dev region\n");
-	return err;
+		class_unregister(&watchdog_class);
+		return err;
+	}
+
+	return 0;
 }
 
 /*
@@ -604,4 +805,5 @@
 void __exit watchdog_dev_exit(void)
 {
 	unregister_chrdev_region(watchdog_devt, MAX_DOGS);
+	class_unregister(&watchdog_class);
 }
diff --git a/drivers/watchdog/ziirave_wdt.c b/drivers/watchdog/ziirave_wdt.c
new file mode 100644
index 0000000..0c7cb73
--- /dev/null
+++ b/drivers/watchdog/ziirave_wdt.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2015 Zodiac Inflight Innovations
+ *
+ * Author: Martyn Welch <martyn.welch@collabora.co.uk>
+ *
+ * Based on twl4030_wdt.c by Timo Kokkonen <timo.t.kokkonen at nokia.com>:
+ *
+ * Copyright (C) Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/watchdog.h>
+
+#define ZIIRAVE_TIMEOUT_MIN	3
+#define ZIIRAVE_TIMEOUT_MAX	255
+
+#define ZIIRAVE_PING_VALUE	0x0
+
+#define ZIIRAVE_STATE_INITIAL	0x0
+#define ZIIRAVE_STATE_OFF	0x1
+#define ZIIRAVE_STATE_ON	0x2
+
+static char *ziirave_reasons[] = {"power cycle", "triggered", NULL, NULL,
+				  "host request", NULL, "illegal configuration",
+				  "illegal instruction", "illegal trap",
+				  "unknown"};
+
+#define ZIIRAVE_WDT_FIRM_VER_MAJOR	0x1
+#define ZIIRAVE_WDT_BOOT_VER_MAJOR	0x3
+#define ZIIRAVE_WDT_RESET_REASON	0x5
+#define ZIIRAVE_WDT_STATE		0x6
+#define ZIIRAVE_WDT_TIMEOUT		0x7
+#define ZIIRAVE_WDT_TIME_LEFT		0x8
+#define ZIIRAVE_WDT_PING		0x9
+#define ZIIRAVE_WDT_RESET_DURATION	0xa
+
+struct ziirave_wdt_rev {
+	unsigned char major;
+	unsigned char minor;
+};
+
+struct ziirave_wdt_data {
+	struct watchdog_device wdd;
+	struct ziirave_wdt_rev bootloader_rev;
+	struct ziirave_wdt_rev firmware_rev;
+	int reset_reason;
+};
+
+static int wdt_timeout;
+module_param(wdt_timeout, int, 0);
+MODULE_PARM_DESC(wdt_timeout, "Watchdog timeout in seconds");
+
+static int reset_duration;
+module_param(reset_duration, int, 0);
+MODULE_PARM_DESC(reset_duration,
+		 "Watchdog reset pulse duration in milliseconds");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started default="
+		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int ziirave_wdt_revision(struct i2c_client *client,
+				struct ziirave_wdt_rev *rev, u8 command)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, command);
+	if (ret < 0)
+		return ret;
+
+	rev->major = ret;
+
+	ret = i2c_smbus_read_byte_data(client, command + 1);
+	if (ret < 0)
+		return ret;
+
+	rev->minor = ret;
+
+	return 0;
+}
+
+static int ziirave_wdt_set_state(struct watchdog_device *wdd, int state)
+{
+	struct i2c_client *client = to_i2c_client(wdd->parent);
+
+	return i2c_smbus_write_byte_data(client, ZIIRAVE_WDT_STATE, state);
+}
+
+static int ziirave_wdt_start(struct watchdog_device *wdd)
+{
+	return ziirave_wdt_set_state(wdd, ZIIRAVE_STATE_ON);
+}
+
+static int ziirave_wdt_stop(struct watchdog_device *wdd)
+{
+	return ziirave_wdt_set_state(wdd, ZIIRAVE_STATE_OFF);
+}
+
+static int ziirave_wdt_ping(struct watchdog_device *wdd)
+{
+	struct i2c_client *client = to_i2c_client(wdd->parent);
+
+	return i2c_smbus_write_byte_data(client, ZIIRAVE_WDT_PING,
+					 ZIIRAVE_PING_VALUE);
+}
+
+static int ziirave_wdt_set_timeout(struct watchdog_device *wdd,
+				   unsigned int timeout)
+{
+	struct i2c_client *client = to_i2c_client(wdd->parent);
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, ZIIRAVE_WDT_TIMEOUT, timeout);
+	if (!ret)
+		wdd->timeout = timeout;
+
+	return ret;
+}
+
+static unsigned int ziirave_wdt_get_timeleft(struct watchdog_device *wdd)
+{
+	struct i2c_client *client = to_i2c_client(wdd->parent);
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, ZIIRAVE_WDT_TIME_LEFT);
+	if (ret < 0)
+		ret = 0;
+
+	return ret;
+}
+
+static const struct watchdog_info ziirave_wdt_info = {
+	.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+	.identity = "Zodiac RAVE Watchdog",
+};
+
+static const struct watchdog_ops ziirave_wdt_ops = {
+	.owner		= THIS_MODULE,
+	.start		= ziirave_wdt_start,
+	.stop		= ziirave_wdt_stop,
+	.ping		= ziirave_wdt_ping,
+	.set_timeout	= ziirave_wdt_set_timeout,
+	.get_timeleft	= ziirave_wdt_get_timeleft,
+};
+
+static ssize_t ziirave_wdt_sysfs_show_firm(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev->parent);
+	struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client);
+
+	return sprintf(buf, "02.%02u.%02u", w_priv->firmware_rev.major,
+		       w_priv->firmware_rev.minor);
+}
+
+static DEVICE_ATTR(firmware_version, S_IRUGO, ziirave_wdt_sysfs_show_firm,
+		   NULL);
+
+static ssize_t ziirave_wdt_sysfs_show_boot(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev->parent);
+	struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client);
+
+	return sprintf(buf, "01.%02u.%02u", w_priv->bootloader_rev.major,
+		       w_priv->bootloader_rev.minor);
+}
+
+static DEVICE_ATTR(bootloader_version, S_IRUGO, ziirave_wdt_sysfs_show_boot,
+		   NULL);
+
+static ssize_t ziirave_wdt_sysfs_show_reason(struct device *dev,
+					     struct device_attribute *attr,
+					     char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev->parent);
+	struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client);
+
+	return sprintf(buf, "%s", ziirave_reasons[w_priv->reset_reason]);
+}
+
+static DEVICE_ATTR(reset_reason, S_IRUGO, ziirave_wdt_sysfs_show_reason,
+		   NULL);
+
+static struct attribute *ziirave_wdt_attrs[] = {
+	&dev_attr_firmware_version.attr,
+	&dev_attr_bootloader_version.attr,
+	&dev_attr_reset_reason.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(ziirave_wdt);
+
+static int ziirave_wdt_init_duration(struct i2c_client *client)
+{
+	int ret;
+
+	if (!reset_duration) {
+		/* See if the reset pulse duration is provided in an of_node */
+		if (!client->dev.of_node)
+			ret = -ENODEV;
+		else
+			ret = of_property_read_u32(client->dev.of_node,
+						   "reset-duration-ms",
+						   &reset_duration);
+		if (ret) {
+			dev_info(&client->dev,
+				 "Unable to set reset pulse duration, using default\n");
+			return 0;
+		}
+	}
+
+	if (reset_duration < 1 || reset_duration > 255)
+		return -EINVAL;
+
+	dev_info(&client->dev, "Setting reset duration to %dms",
+		 reset_duration);
+
+	return i2c_smbus_write_byte_data(client, ZIIRAVE_WDT_RESET_DURATION,
+					 reset_duration);
+}
+
+static int ziirave_wdt_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	int ret;
+	struct ziirave_wdt_data *w_priv;
+	int val;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	w_priv = devm_kzalloc(&client->dev, sizeof(*w_priv), GFP_KERNEL);
+	if (!w_priv)
+		return -ENOMEM;
+
+	w_priv->wdd.info = &ziirave_wdt_info;
+	w_priv->wdd.ops = &ziirave_wdt_ops;
+	w_priv->wdd.min_timeout = ZIIRAVE_TIMEOUT_MIN;
+	w_priv->wdd.max_timeout = ZIIRAVE_TIMEOUT_MAX;
+	w_priv->wdd.parent = &client->dev;
+	w_priv->wdd.groups = ziirave_wdt_groups;
+
+	ret = watchdog_init_timeout(&w_priv->wdd, wdt_timeout, &client->dev);
+	if (ret) {
+		dev_info(&client->dev,
+			 "Unable to select timeout value, using default\n");
+	}
+
+	/*
+	 * The default value set in the watchdog should be perfectly valid, so
+	 * pass that in if we haven't provided one via the module parameter or
+	 * of property.
+	 */
+	if (w_priv->wdd.timeout == 0) {
+		val = i2c_smbus_read_byte_data(client, ZIIRAVE_WDT_TIMEOUT);
+		if (val < 0)
+			return val;
+
+		if (val < ZIIRAVE_TIMEOUT_MIN)
+			return -ENODEV;
+
+		w_priv->wdd.timeout = val;
+	} else {
+		ret = ziirave_wdt_set_timeout(&w_priv->wdd,
+					      w_priv->wdd.timeout);
+		if (ret)
+			return ret;
+
+		dev_info(&client->dev, "Timeout set to %ds.",
+			 w_priv->wdd.timeout);
+	}
+
+	watchdog_set_nowayout(&w_priv->wdd, nowayout);
+
+	i2c_set_clientdata(client, w_priv);
+
+	/* If in unconfigured state, set to stopped */
+	val = i2c_smbus_read_byte_data(client, ZIIRAVE_WDT_STATE);
+	if (val < 0)
+		return val;
+
+	if (val == ZIIRAVE_STATE_INITIAL)
+		ziirave_wdt_stop(&w_priv->wdd);
+
+	ret = ziirave_wdt_init_duration(client);
+	if (ret)
+		return ret;
+
+	ret = ziirave_wdt_revision(client, &w_priv->firmware_rev,
+				   ZIIRAVE_WDT_FIRM_VER_MAJOR);
+	if (ret)
+		return ret;
+
+	ret = ziirave_wdt_revision(client, &w_priv->bootloader_rev,
+				   ZIIRAVE_WDT_BOOT_VER_MAJOR);
+	if (ret)
+		return ret;
+
+	w_priv->reset_reason = i2c_smbus_read_byte_data(client,
+						ZIIRAVE_WDT_RESET_REASON);
+	if (w_priv->reset_reason < 0)
+		return w_priv->reset_reason;
+
+	if (w_priv->reset_reason >= ARRAY_SIZE(ziirave_reasons) ||
+	    !ziirave_reasons[w_priv->reset_reason])
+		return -ENODEV;
+
+	ret = watchdog_register_device(&w_priv->wdd);
+
+	return ret;
+}
+
+static int ziirave_wdt_remove(struct i2c_client *client)
+{
+	struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client);
+
+	watchdog_unregister_device(&w_priv->wdd);
+
+	return 0;
+}
+
+static struct i2c_device_id ziirave_wdt_id[] = {
+	{ "ziirave-wdt", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ziirave_wdt_id);
+
+static const struct of_device_id zrv_wdt_of_match[] = {
+	{ .compatible = "zii,rave-wdt", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, zrv_wdt_of_match);
+
+static struct i2c_driver ziirave_wdt_driver = {
+	.driver = {
+		.name = "ziirave_wdt",
+		.of_match_table = zrv_wdt_of_match,
+	},
+	.probe = ziirave_wdt_probe,
+	.remove = ziirave_wdt_remove,
+	.id_table = ziirave_wdt_id,
+};
+
+module_i2c_driver(ziirave_wdt_driver);
+
+MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.co.uk");
+MODULE_DESCRIPTION("Zodiac Aerospace RAVE Switch Watchdog Processor Driver");
+MODULE_LICENSE("GPL");
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 0a271ca..a8e01aa 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -349,6 +349,8 @@
 	struct list_head event_list;
 	int event_space;
 
+	struct mutex event_read_lock;
+
 	struct drm_prime_file_private prime;
 };
 
@@ -1121,4 +1123,7 @@
 	return true;
 }
 
+/* helper for handling conditionals in various for_each macros */
+#define for_each_if(condition) if (!(condition)) {} else
+
 #endif
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 4b74c97..d8576ac 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -149,7 +149,7 @@
 	     ((connector) = (state)->connectors[__i],			\
 	     (connector_state) = (state)->connector_states[__i], 1); 	\
 	     (__i)++)							\
-		if (connector)
+		for_each_if (connector)
 
 #define for_each_crtc_in_state(state, crtc, crtc_state, __i)	\
 	for ((__i) = 0;						\
@@ -157,7 +157,7 @@
 	     ((crtc) = (state)->crtcs[__i],			\
 	     (crtc_state) = (state)->crtc_states[__i], 1);	\
 	     (__i)++)						\
-		if (crtc_state)
+		for_each_if (crtc_state)
 
 #define for_each_plane_in_state(state, plane, plane_state, __i)		\
 	for ((__i) = 0;							\
@@ -165,7 +165,7 @@
 	     ((plane) = (state)->planes[__i],				\
 	     (plane_state) = (state)->plane_states[__i], 1);		\
 	     (__i)++)							\
-		if (plane_state)
+		for_each_if (plane_state)
 static inline bool
 drm_atomic_crtc_needs_modeset(struct drm_crtc_state *state)
 {
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 8cba54a..a286cce 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -62,6 +62,8 @@
 void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
 				      struct drm_atomic_state *old_state);
 void drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state);
+void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc,
+					      bool atomic);
 
 void drm_atomic_helper_swap_state(struct drm_device *dev,
 				  struct drm_atomic_state *state);
@@ -81,6 +83,12 @@
 int __drm_atomic_helper_set_config(struct drm_mode_set *set,
 		struct drm_atomic_state *state);
 
+int drm_atomic_helper_disable_all(struct drm_device *dev,
+				  struct drm_modeset_acquire_ctx *ctx);
+struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev);
+int drm_atomic_helper_resume(struct drm_device *dev,
+			     struct drm_atomic_state *state);
+
 int drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc,
 					struct drm_property *property,
 					uint64_t val);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3f0c690..4765df3 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -85,7 +85,11 @@
 	return (uint64_t)*((uint64_t *)&val);
 }
 
-/* rotation property bits */
+/*
+ * Rotation property bits. DRM_ROTATE_<degrees> rotates the image by the
+ * specified amount in degrees in counter clockwise direction. DRM_REFLECT_X and
+ * DRM_REFLECT_Y reflects the image along the specified axis prior to rotation
+ */
 #define DRM_ROTATE_MASK 0x0f
 #define DRM_ROTATE_0	0
 #define DRM_ROTATE_90	1
@@ -992,7 +996,7 @@
 struct drm_mode_config_funcs {
 	struct drm_framebuffer *(*fb_create)(struct drm_device *dev,
 					     struct drm_file *file_priv,
-					     struct drm_mode_fb_cmd2 *mode_cmd);
+					     const struct drm_mode_fb_cmd2 *mode_cmd);
 	void (*output_poll_changed)(struct drm_device *dev);
 
 	int (*atomic_check)(struct drm_device *dev,
@@ -1166,7 +1170,7 @@
  */
 #define drm_for_each_plane_mask(plane, dev, plane_mask) \
 	list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \
-		if ((plane_mask) & (1 << drm_plane_index(plane)))
+		for_each_if ((plane_mask) & (1 << drm_plane_index(plane)))
 
 
 #define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
@@ -1543,7 +1547,7 @@
 /* Plane list iterator for legacy (overlay only) planes. */
 #define drm_for_each_legacy_plane(plane, dev) \
 	list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \
-		if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+		for_each_if (plane->type == DRM_PLANE_TYPE_OVERLAY)
 
 #define drm_for_each_plane(plane, dev) \
 	list_for_each_entry(plane, &(dev)->mode_config.plane_list, head)
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index 3febb4b..e22ab29 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -197,7 +197,7 @@
 extern void drm_helper_move_panel_connectors_to_head(struct drm_device *);
 
 extern void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
-					   struct drm_mode_fb_cmd2 *mode_cmd);
+					   const struct drm_mode_fb_cmd2 *mode_cmd);
 
 static inline void drm_crtc_helper_add(struct drm_crtc *crtc,
 				       const struct drm_crtc_helper_funcs *funcs)
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index bb9d0de..1252108 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -455,16 +455,52 @@
 # define DP_EDP_14			    0x03
 
 #define DP_EDP_GENERAL_CAP_1		    0x701
+# define DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP		(1 << 0)
+# define DP_EDP_BACKLIGHT_PIN_ENABLE_CAP		(1 << 1)
+# define DP_EDP_BACKLIGHT_AUX_ENABLE_CAP		(1 << 2)
+# define DP_EDP_PANEL_SELF_TEST_PIN_ENABLE_CAP		(1 << 3)
+# define DP_EDP_PANEL_SELF_TEST_AUX_ENABLE_CAP		(1 << 4)
+# define DP_EDP_FRC_ENABLE_CAP				(1 << 5)
+# define DP_EDP_COLOR_ENGINE_CAP			(1 << 6)
+# define DP_EDP_SET_POWER_CAP				(1 << 7)
 
 #define DP_EDP_BACKLIGHT_ADJUSTMENT_CAP     0x702
+# define DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP	(1 << 0)
+# define DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP	(1 << 1)
+# define DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT		(1 << 2)
+# define DP_EDP_BACKLIGHT_AUX_PWM_PRODUCT_CAP		(1 << 3)
+# define DP_EDP_BACKLIGHT_FREQ_PWM_PIN_PASSTHRU_CAP	(1 << 4)
+# define DP_EDP_BACKLIGHT_FREQ_AUX_SET_CAP		(1 << 5)
+# define DP_EDP_DYNAMIC_BACKLIGHT_CAP			(1 << 6)
+# define DP_EDP_VBLANK_BACKLIGHT_UPDATE_CAP		(1 << 7)
 
 #define DP_EDP_GENERAL_CAP_2		    0x703
+# define DP_EDP_OVERDRIVE_ENGINE_ENABLED		(1 << 0)
 
 #define DP_EDP_GENERAL_CAP_3		    0x704    /* eDP 1.4 */
+# define DP_EDP_X_REGION_CAP_MASK			(0xf << 0)
+# define DP_EDP_X_REGION_CAP_SHIFT			0
+# define DP_EDP_Y_REGION_CAP_MASK			(0xf << 4)
+# define DP_EDP_Y_REGION_CAP_SHIFT			4
 
 #define DP_EDP_DISPLAY_CONTROL_REGISTER     0x720
+# define DP_EDP_BACKLIGHT_ENABLE			(1 << 0)
+# define DP_EDP_BLACK_VIDEO_ENABLE			(1 << 1)
+# define DP_EDP_FRC_ENABLE				(1 << 2)
+# define DP_EDP_COLOR_ENGINE_ENABLE			(1 << 3)
+# define DP_EDP_VBLANK_BACKLIGHT_UPDATE_ENABLE		(1 << 7)
 
 #define DP_EDP_BACKLIGHT_MODE_SET_REGISTER  0x721
+# define DP_EDP_BACKLIGHT_CONTROL_MODE_MASK		(3 << 0)
+# define DP_EDP_BACKLIGHT_CONTROL_MODE_PWM		(0 << 0)
+# define DP_EDP_BACKLIGHT_CONTROL_MODE_PRESET		(1 << 0)
+# define DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD		(2 << 0)
+# define DP_EDP_BACKLIGHT_CONTROL_MODE_PRODUCT		(3 << 0)
+# define DP_EDP_BACKLIGHT_FREQ_PWM_PIN_PASSTHRU_ENABLE	(1 << 2)
+# define DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE		(1 << 3)
+# define DP_EDP_DYNAMIC_BACKLIGHT_ENABLE		(1 << 4)
+# define DP_EDP_REGIONAL_BACKLIGHT_ENABLE		(1 << 5)
+# define DP_EDP_UPDATE_REGION_BRIGHTNESS		(1 << 6) /* eDP 1.4 */
 
 #define DP_EDP_BACKLIGHT_BRIGHTNESS_MSB     0x722
 #define DP_EDP_BACKLIGHT_BRIGHTNESS_LSB     0x723
diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h
index c54cf3d..be62bd3 100644
--- a/include/drm/drm_fb_cma_helper.h
+++ b/include/drm/drm_fb_cma_helper.h
@@ -18,7 +18,7 @@
 void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma);
 
 struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev,
-	struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd);
+	struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd);
 
 struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
 	unsigned int plane);
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index 15e7f00..0b3e11a 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -35,76 +35,129 @@
  */
 
 /**
- * This structure defines the drm_mm memory object, which will be used by the
- * DRM for its buffer objects.
+ * struct drm_gem_object - GEM buffer object
+ *
+ * This structure defines the generic parts for GEM buffer objects, which are
+ * mostly around handling mmap and userspace handles.
+ *
+ * Buffer objects are often abbreviated to BO.
  */
 struct drm_gem_object {
-	/** Reference count of this object */
+	/**
+	 * @refcount:
+	 *
+	 * Reference count of this object
+	 *
+	 * Please use drm_gem_object_reference() to acquire and
+	 * drm_gem_object_unreference() or drm_gem_object_unreference_unlocked()
+	 * to release a reference to a GEM buffer object.
+	 */
 	struct kref refcount;
 
 	/**
-	 * handle_count - gem file_priv handle count of this object
+	 * @handle_count:
+	 *
+	 * This is the GEM file_priv handle count of this object.
 	 *
 	 * Each handle also holds a reference. Note that when the handle_count
 	 * drops to 0 any global names (e.g. the id in the flink namespace) will
 	 * be cleared.
 	 *
 	 * Protected by dev->object_name_lock.
-	 * */
+	 */
 	unsigned handle_count;
 
-	/** Related drm device */
+	/**
+	 * @dev: DRM dev this object belongs to.
+	 */
 	struct drm_device *dev;
 
-	/** File representing the shmem storage */
+	/**
+	 * @filp:
+	 *
+	 * SHMEM file node used as backing storage for swappable buffer objects.
+	 * GEM also supports driver private objects with driver-specific backing
+	 * storage (contiguous CMA memory, special reserved blocks). In this
+	 * case @filp is NULL.
+	 */
 	struct file *filp;
 
-	/* Mapping info for this object */
+	/**
+	 * @vma_node:
+	 *
+	 * Mapping info for this object to support mmap. Drivers are supposed to
+	 * allocate the mmap offset using drm_gem_create_mmap_offset(). The
+	 * offset itself can be retrieved using drm_vma_node_offset_addr().
+	 *
+	 * Memory mapping itself is handled by drm_gem_mmap(), which also checks
+	 * that userspace is allowed to access the object.
+	 */
 	struct drm_vma_offset_node vma_node;
 
 	/**
+	 * @size:
+	 *
 	 * Size of the object, in bytes.  Immutable over the object's
 	 * lifetime.
 	 */
 	size_t size;
 
 	/**
+	 * @name:
+	 *
 	 * Global name for this object, starts at 1. 0 means unnamed.
-	 * Access is covered by the object_name_lock in the related drm_device
+	 * Access is covered by dev->object_name_lock. This is used by the GEM_FLINK
+	 * and GEM_OPEN ioctls.
 	 */
 	int name;
 
 	/**
-	 * Memory domains. These monitor which caches contain read/write data
+	 * @read_domains:
+	 *
+	 * Read memory domains. These monitor which caches contain read/write data
 	 * related to the object. When transitioning from one set of domains
 	 * to another, the driver is called to ensure that caches are suitably
-	 * flushed and invalidated
+	 * flushed and invalidated.
 	 */
 	uint32_t read_domains;
+
+	/**
+	 * @write_domain: Corresponding unique write memory domain.
+	 */
 	uint32_t write_domain;
 
 	/**
+	 * @pending_read_domains:
+	 *
 	 * While validating an exec operation, the
 	 * new read/write domain values are computed here.
 	 * They will be transferred to the above values
 	 * at the point that any cache flushing occurs
 	 */
 	uint32_t pending_read_domains;
+
+	/**
+	 * @pending_write_domain: Write domain similar to @pending_read_domains.
+	 */
 	uint32_t pending_write_domain;
 
 	/**
-	 * dma_buf - dma buf associated with this GEM object
+	 * @dma_buf:
+	 *
+	 * dma-buf associated with this GEM object.
 	 *
 	 * Pointer to the dma-buf associated with this gem object (either
 	 * through importing or exporting). We break the resulting reference
 	 * loop when the last gem handle for this object is released.
 	 *
-	 * Protected by obj->object_name_lock
+	 * Protected by obj->object_name_lock.
 	 */
 	struct dma_buf *dma_buf;
 
 	/**
-	 * import_attach - dma buf attachment backing this object
+	 * @import_attach:
+	 *
+	 * dma-buf attachment backing this object.
 	 *
 	 * Any foreign dma_buf imported as a gem object has this set to the
 	 * attachment point for the device. This is invariant over the lifetime
@@ -133,12 +186,30 @@
 		     struct vm_area_struct *vma);
 int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
 
+/**
+ * drm_gem_object_reference - acquire a GEM BO reference
+ * @obj: GEM buffer object
+ *
+ * This acquires additional reference to @obj. It is illegal to call this
+ * without already holding a reference. No locks required.
+ */
 static inline void
 drm_gem_object_reference(struct drm_gem_object *obj)
 {
 	kref_get(&obj->refcount);
 }
 
+/**
+ * drm_gem_object_unreference - release a GEM BO reference
+ * @obj: GEM buffer object
+ *
+ * This releases a reference to @obj. Callers must hold the dev->struct_mutex
+ * lock when calling this function, even when the driver doesn't use
+ * dev->struct_mutex for anything.
+ *
+ * For drivers not encumbered with legacy locking use
+ * drm_gem_object_unreference_unlocked() instead.
+ */
 static inline void
 drm_gem_object_unreference(struct drm_gem_object *obj)
 {
@@ -149,6 +220,13 @@
 	}
 }
 
+/**
+ * drm_gem_object_unreference_unlocked - release a GEM BO reference
+ * @obj: GEM buffer object
+ *
+ * This releases a reference to @obj. Callers must not hold the
+ * dev->struct_mutex lock when calling this function.
+ */
 static inline void
 drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
 {
diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h
index 0de6290..fc65118 100644
--- a/include/drm/drm_mm.h
+++ b/include/drm/drm_mm.h
@@ -148,8 +148,7 @@
 
 static inline u64 __drm_mm_hole_node_end(struct drm_mm_node *hole_node)
 {
-	return list_entry(hole_node->node_list.next,
-			  struct drm_mm_node, node_list)->start;
+	return list_next_entry(hole_node, node_list)->start;
 }
 
 /**
@@ -180,6 +179,14 @@
 						&(mm)->head_node.node_list, \
 						node_list)
 
+#define __drm_mm_for_each_hole(entry, mm, hole_start, hole_end, backwards) \
+	for (entry = list_entry((backwards) ? (mm)->hole_stack.prev : (mm)->hole_stack.next, struct drm_mm_node, hole_stack); \
+	     &entry->hole_stack != &(mm)->hole_stack ? \
+	     hole_start = drm_mm_hole_node_start(entry), \
+	     hole_end = drm_mm_hole_node_end(entry), \
+	     1 : 0; \
+	     entry = list_entry((backwards) ? entry->hole_stack.prev : entry->hole_stack.next, struct drm_mm_node, hole_stack))
+
 /**
  * drm_mm_for_each_hole - iterator to walk over all holes
  * @entry: drm_mm_node used internally to track progress
@@ -200,20 +207,7 @@
  * going backwards.
  */
 #define drm_mm_for_each_hole(entry, mm, hole_start, hole_end) \
-	for (entry = list_entry((mm)->hole_stack.next, struct drm_mm_node, hole_stack); \
-	     &entry->hole_stack != &(mm)->hole_stack ? \
-	     hole_start = drm_mm_hole_node_start(entry), \
-	     hole_end = drm_mm_hole_node_end(entry), \
-	     1 : 0; \
-	     entry = list_entry(entry->hole_stack.next, struct drm_mm_node, hole_stack))
-
-#define __drm_mm_for_each_hole(entry, mm, hole_start, hole_end, backwards) \
-	for (entry = list_entry((backwards) ? (mm)->hole_stack.prev : (mm)->hole_stack.next, struct drm_mm_node, hole_stack); \
-	     &entry->hole_stack != &(mm)->hole_stack ? \
-	     hole_start = drm_mm_hole_node_start(entry), \
-	     hole_end = drm_mm_hole_node_end(entry), \
-	     1 : 0; \
-	     entry = list_entry((backwards) ? entry->hole_stack.prev : entry->hole_stack.next, struct drm_mm_node, hole_stack))
+	__drm_mm_for_each_hole(entry, mm, hole_start, hole_end, 0)
 
 /*
  * Basic range manager support (drm_mm.c)
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h
index 08a8cac..f9115ae 100644
--- a/include/drm/drm_modes.h
+++ b/include/drm/drm_modes.h
@@ -222,6 +222,8 @@
 					    const struct drm_display_mode *mode);
 bool drm_mode_equal(const struct drm_display_mode *mode1,
 		    const struct drm_display_mode *mode2);
+bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1,
+			      const struct drm_display_mode *mode2);
 bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
 					const struct drm_display_mode *mode2);
 
diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h
index 94938d8..c5576fb 100644
--- a/include/drm/drm_modeset_lock.h
+++ b/include/drm/drm_modeset_lock.h
@@ -138,7 +138,7 @@
 struct drm_modeset_acquire_ctx *
 drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc);
 
-int drm_modeset_lock_all_crtcs(struct drm_device *dev,
-		struct drm_modeset_acquire_ctx *ctx);
+int drm_modeset_lock_all_ctx(struct drm_device *dev,
+			     struct drm_modeset_acquire_ctx *ctx);
 
 #endif /* DRM_MODESET_LOCK_H_ */
diff --git a/include/drm/drm_rect.h b/include/drm/drm_rect.h
index 26bb55e..83bb156 100644
--- a/include/drm/drm_rect.h
+++ b/include/drm/drm_rect.h
@@ -162,7 +162,8 @@
 int drm_rect_calc_vscale_relaxed(struct drm_rect *src,
 				 struct drm_rect *dst,
 				 int min_vscale, int max_vscale);
-void drm_rect_debug_print(const struct drm_rect *r, bool fixed_point);
+void drm_rect_debug_print(const char *prefix,
+			  const struct drm_rect *r, bool fixed_point);
 void drm_rect_rotate(struct drm_rect *r,
 		     int width, int height,
 		     unsigned int rotation);
diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h
index 30d89e0..b46fa0e 100644
--- a/include/drm/i915_component.h
+++ b/include/drm/i915_component.h
@@ -31,47 +31,94 @@
 #define MAX_PORTS 5
 
 /**
- * struct i915_audio_component_ops - callbacks defined in gfx driver
- * @owner: the module owner
- * @get_power: get the POWER_DOMAIN_AUDIO power well
- * @put_power: put the POWER_DOMAIN_AUDIO power well
- * @codec_wake_override: Enable/Disable generating the codec wake signal
- * @get_cdclk_freq: get the Core Display Clock in KHz
- * @sync_audio_rate: set n/cts based on the sample rate
+ * struct i915_audio_component_ops - Ops implemented by i915 driver, called by hda driver
  */
 struct i915_audio_component_ops {
+	/**
+	 * @owner: i915 module
+	 */
 	struct module *owner;
+	/**
+	 * @get_power: get the POWER_DOMAIN_AUDIO power well
+	 *
+	 * Request the power well to be turned on.
+	 */
 	void (*get_power)(struct device *);
+	/**
+	 * @put_power: put the POWER_DOMAIN_AUDIO power well
+	 *
+	 * Allow the power well to be turned off.
+	 */
 	void (*put_power)(struct device *);
+	/**
+	 * @codec_wake_override: Enable/disable codec wake signal
+	 */
 	void (*codec_wake_override)(struct device *, bool enable);
+	/**
+	 * @get_cdclk_freq: Get the Core Display Clock in kHz
+	 */
 	int (*get_cdclk_freq)(struct device *);
+	/**
+	 * @sync_audio_rate: set n/cts based on the sample rate
+	 *
+	 * Called from audio driver. After audio driver sets the
+	 * sample rate, it will call this function to set n/cts
+	 */
 	int (*sync_audio_rate)(struct device *, int port, int rate);
+	/**
+	 * @get_eld: fill the audio state and ELD bytes for the given port
+	 *
+	 * Called from audio driver to get the HDMI/DP audio state of the given
+	 * digital port, and also fetch ELD bytes to the given pointer.
+	 *
+	 * It returns the byte size of the original ELD (not the actually
+	 * copied size), zero for an invalid ELD, or a negative error code.
+	 *
+	 * Note that the returned size may be over @max_bytes.  Then it
+	 * implies that only a part of ELD has been copied to the buffer.
+	 */
+	int (*get_eld)(struct device *, int port, bool *enabled,
+		       unsigned char *buf, int max_bytes);
 };
 
+/**
+ * struct i915_audio_component_audio_ops - Ops implemented by hda driver, called by i915 driver
+ */
 struct i915_audio_component_audio_ops {
+	/**
+	 * @audio_ptr: Pointer to be used in call to pin_eld_notify
+	 */
 	void *audio_ptr;
 	/**
-	 * Call from i915 driver, notifying the HDA driver that
-	 * pin sense and/or ELD information has changed.
-	 * @audio_ptr:		HDA driver object
-	 * @port:	Which port has changed (PORTA / PORTB / PORTC etc)
+	 * @pin_eld_notify: Notify the HDA driver that pin sense and/or ELD information has changed
+	 *
+	 * Called when the i915 driver has set up audio pipeline or has just
+	 * begun to tear it down. This allows the HDA driver to update its
+	 * status accordingly (even when the HDA controller is in power save
+	 * mode).
 	 */
 	void (*pin_eld_notify)(void *audio_ptr, int port);
 };
 
 /**
- * struct i915_audio_component - used for audio video interaction
- * @dev: the device from gfx driver
- * @aud_sample_rate: the array of audio sample rate per port
- * @ops: callback for audio driver calling
- * @audio_ops: Call from i915 driver
+ * struct i915_audio_component - Used for direct communication between i915 and hda drivers
  */
 struct i915_audio_component {
+	/**
+	 * @dev: i915 device, used as parameter for ops
+	 */
 	struct device *dev;
+	/**
+	 * @aud_sample_rate: the array of audio sample rate per port
+	 */
 	int aud_sample_rate[MAX_PORTS];
-
+	/**
+	 * @ops: Ops implemented by i915 driver, called by hda driver
+	 */
 	const struct i915_audio_component_ops *ops;
-
+	/**
+	 * @audio_ops: Ops implemented by hda driver, called by i915 driver
+	 */
 	const struct i915_audio_component_audio_ops *audio_ops;
 };
 
diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h
index 17c4456..f1a113e 100644
--- a/include/drm/i915_pciids.h
+++ b/include/drm/i915_pciids.h
@@ -291,4 +291,40 @@
 	INTEL_VGA_DEVICE(0x1A84, info), \
 	INTEL_VGA_DEVICE(0x5A84, info)
 
+#define INTEL_KBL_GT1_IDS(info)	\
+	INTEL_VGA_DEVICE(0x5913, info), /* ULT GT1.5 */ \
+	INTEL_VGA_DEVICE(0x5915, info), /* ULX GT1.5 */ \
+	INTEL_VGA_DEVICE(0x5917, info), /* DT  GT1.5 */ \
+	INTEL_VGA_DEVICE(0x5906, info), /* ULT GT1 */ \
+	INTEL_VGA_DEVICE(0x590E, info), /* ULX GT1 */ \
+	INTEL_VGA_DEVICE(0x5902, info), /* DT  GT1 */ \
+	INTEL_VGA_DEVICE(0x590B, info), /* Halo GT1 */ \
+	INTEL_VGA_DEVICE(0x590A, info) /* SRV GT1 */
+
+#define INTEL_KBL_GT2_IDS(info)	\
+	INTEL_VGA_DEVICE(0x5916, info), /* ULT GT2 */ \
+	INTEL_VGA_DEVICE(0x5921, info), /* ULT GT2F */ \
+	INTEL_VGA_DEVICE(0x591E, info), /* ULX GT2 */ \
+	INTEL_VGA_DEVICE(0x5912, info), /* DT  GT2 */ \
+	INTEL_VGA_DEVICE(0x591B, info), /* Halo GT2 */ \
+	INTEL_VGA_DEVICE(0x591A, info), /* SRV GT2 */ \
+	INTEL_VGA_DEVICE(0x591D, info) /* WKS GT2 */
+
+#define INTEL_KBL_GT3_IDS(info) \
+	INTEL_VGA_DEVICE(0x5926, info), /* ULT GT3 */ \
+	INTEL_VGA_DEVICE(0x592B, info), /* Halo GT3 */ \
+	INTEL_VGA_DEVICE(0x592A, info) /* SRV GT3 */
+
+#define INTEL_KBL_GT4_IDS(info) \
+	INTEL_VGA_DEVICE(0x5932, info), /* DT  GT4 */ \
+	INTEL_VGA_DEVICE(0x593B, info), /* Halo GT4 */ \
+	INTEL_VGA_DEVICE(0x593A, info), /* SRV GT4 */ \
+	INTEL_VGA_DEVICE(0x593D, info)  /* WKS GT4 */
+
+#define INTEL_KBL_IDS(info) \
+	INTEL_KBL_GT1_IDS(info), \
+	INTEL_KBL_GT2_IDS(info), \
+	INTEL_KBL_GT3_IDS(info), \
+	INTEL_KBL_GT4_IDS(info)
+
 #endif /* _I915_PCIIDS_H */
diff --git a/include/dt-bindings/clock/bcm2835-aux.h b/include/dt-bindings/clock/bcm2835-aux.h
new file mode 100644
index 0000000..d91156e
--- /dev/null
+++ b/include/dt-bindings/clock/bcm2835-aux.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define BCM2835_AUX_CLOCK_UART		0
+#define BCM2835_AUX_CLOCK_SPI1		1
+#define BCM2835_AUX_CLOCK_SPI2		2
+#define BCM2835_AUX_CLOCK_COUNT		3
diff --git a/include/dt-bindings/clock/bcm2835.h b/include/dt-bindings/clock/bcm2835.h
index d323efa..61f1d20 100644
--- a/include/dt-bindings/clock/bcm2835.h
+++ b/include/dt-bindings/clock/bcm2835.h
@@ -43,5 +43,6 @@
 #define BCM2835_CLOCK_TSENS		27
 #define BCM2835_CLOCK_EMMC		28
 #define BCM2835_CLOCK_PERI_IMAGE	29
+#define BCM2835_CLOCK_PWM		30
 
-#define BCM2835_CLOCK_COUNT		30
+#define BCM2835_CLOCK_COUNT		31
diff --git a/include/dt-bindings/clock/exynos5420.h b/include/dt-bindings/clock/exynos5420.h
index 99da0d1..7699ee9 100644
--- a/include/dt-bindings/clock/exynos5420.h
+++ b/include/dt-bindings/clock/exynos5420.h
@@ -25,6 +25,8 @@
 #define CLK_FOUT_MPLL		10
 #define CLK_FOUT_BPLL		11
 #define CLK_FOUT_KPLL		12
+#define CLK_ARM_CLK		13
+#define CLK_KFC_CLK		14
 
 /* gate for special clocks (sclk) */
 #define CLK_SCLK_UART0		128
@@ -210,6 +212,8 @@
 #define CLK_MOUT_SW_ACLK300     649
 #define CLK_MOUT_USER_ACLK400_DISP1     650
 #define CLK_MOUT_SW_ACLK400     651
+#define CLK_MOUT_USER_ACLK300_GSCL	652
+#define CLK_MOUT_SW_ACLK300_GSCL	653
 
 /* divider clocks */
 #define CLK_DOUT_PIXEL		768
diff --git a/include/dt-bindings/clock/imx7d-clock.h b/include/dt-bindings/clock/imx7d-clock.h
index a4a7a9c..edca8985c 100644
--- a/include/dt-bindings/clock/imx7d-clock.h
+++ b/include/dt-bindings/clock/imx7d-clock.h
@@ -447,5 +447,6 @@
 #define IMX7D_SEMA4_HS_ROOT_CLK		434
 #define IMX7D_PLL_DRAM_TEST_DIV		435
 #define IMX7D_ADC_ROOT_CLK		436
-#define IMX7D_CLK_END			437
+#define IMX7D_CLK_ARM			437
+#define IMX7D_CLK_END			438
 #endif /* __DT_BINDINGS_CLOCK_IMX7D_H */
diff --git a/include/dt-bindings/clock/lpc32xx-clock.h b/include/dt-bindings/clock/lpc32xx-clock.h
new file mode 100644
index 0000000..bcb1c9a
--- /dev/null
+++ b/include/dt-bindings/clock/lpc32xx-clock.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015 Vladimir Zapolskiy <vz@mleia.com>
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the licence that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ *
+ */
+
+#ifndef __DT_BINDINGS_LPC32XX_CLOCK_H
+#define __DT_BINDINGS_LPC32XX_CLOCK_H
+
+/* LPC32XX System Control Block clocks */
+#define LPC32XX_CLK_RTC		1
+#define LPC32XX_CLK_DMA		2
+#define LPC32XX_CLK_MLC		3
+#define LPC32XX_CLK_SLC		4
+#define LPC32XX_CLK_LCD		5
+#define LPC32XX_CLK_MAC		6
+#define LPC32XX_CLK_SD		7
+#define LPC32XX_CLK_DDRAM	8
+#define LPC32XX_CLK_SSP0	9
+#define LPC32XX_CLK_SSP1	10
+#define LPC32XX_CLK_UART3	11
+#define LPC32XX_CLK_UART4	12
+#define LPC32XX_CLK_UART5	13
+#define LPC32XX_CLK_UART6	14
+#define LPC32XX_CLK_IRDA	15
+#define LPC32XX_CLK_I2C1	16
+#define LPC32XX_CLK_I2C2	17
+#define LPC32XX_CLK_TIMER0	18
+#define LPC32XX_CLK_TIMER1	19
+#define LPC32XX_CLK_TIMER2	20
+#define LPC32XX_CLK_TIMER3	21
+#define LPC32XX_CLK_TIMER4	22
+#define LPC32XX_CLK_TIMER5	23
+#define LPC32XX_CLK_WDOG	24
+#define LPC32XX_CLK_I2S0	25
+#define LPC32XX_CLK_I2S1	26
+#define LPC32XX_CLK_SPI1	27
+#define LPC32XX_CLK_SPI2	28
+#define LPC32XX_CLK_MCPWM	29
+#define LPC32XX_CLK_HSTIMER	30
+#define LPC32XX_CLK_KEY		31
+#define LPC32XX_CLK_PWM1	32
+#define LPC32XX_CLK_PWM2	33
+#define LPC32XX_CLK_ADC		34
+
+/* LPC32XX USB clocks */
+#define LPC32XX_USB_CLK_I2C	1
+#define LPC32XX_USB_CLK_DEVICE	2
+#define LPC32XX_USB_CLK_HOST	3
+
+#endif /* __DT_BINDINGS_LPC32XX_CLOCK_H */
diff --git a/include/dt-bindings/clock/qcom,gcc-msm8996.h b/include/dt-bindings/clock/qcom,gcc-msm8996.h
new file mode 100644
index 0000000..888e75c
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,gcc-msm8996.h
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DT_BINDINGS_CLK_MSM_GCC_8996_H
+#define _DT_BINDINGS_CLK_MSM_GCC_8996_H
+
+#define GPLL0_EARLY						0
+#define GPLL0							1
+#define GPLL1_EARLY						2
+#define GPLL1							3
+#define GPLL2_EARLY						4
+#define GPLL2							5
+#define GPLL3_EARLY						6
+#define GPLL3							7
+#define GPLL4_EARLY						8
+#define GPLL4							9
+#define SYSTEM_NOC_CLK_SRC					10
+#define CONFIG_NOC_CLK_SRC					11
+#define PERIPH_NOC_CLK_SRC					12
+#define MMSS_BIMC_GFX_CLK_SRC					13
+#define USB30_MASTER_CLK_SRC					14
+#define USB30_MOCK_UTMI_CLK_SRC					15
+#define USB3_PHY_AUX_CLK_SRC					16
+#define USB20_MASTER_CLK_SRC					17
+#define USB20_MOCK_UTMI_CLK_SRC					18
+#define SDCC1_APPS_CLK_SRC					19
+#define SDCC1_ICE_CORE_CLK_SRC					20
+#define SDCC2_APPS_CLK_SRC					21
+#define SDCC3_APPS_CLK_SRC					22
+#define SDCC4_APPS_CLK_SRC					23
+#define BLSP1_QUP1_SPI_APPS_CLK_SRC				24
+#define BLSP1_QUP1_I2C_APPS_CLK_SRC				25
+#define BLSP1_UART1_APPS_CLK_SRC				26
+#define BLSP1_QUP2_SPI_APPS_CLK_SRC				27
+#define BLSP1_QUP2_I2C_APPS_CLK_SRC				28
+#define BLSP1_UART2_APPS_CLK_SRC				29
+#define BLSP1_QUP3_SPI_APPS_CLK_SRC				30
+#define BLSP1_QUP3_I2C_APPS_CLK_SRC				31
+#define BLSP1_UART3_APPS_CLK_SRC				32
+#define BLSP1_QUP4_SPI_APPS_CLK_SRC				33
+#define BLSP1_QUP4_I2C_APPS_CLK_SRC				34
+#define BLSP1_UART4_APPS_CLK_SRC				35
+#define BLSP1_QUP5_SPI_APPS_CLK_SRC				36
+#define BLSP1_QUP5_I2C_APPS_CLK_SRC				37
+#define BLSP1_UART5_APPS_CLK_SRC				38
+#define BLSP1_QUP6_SPI_APPS_CLK_SRC				39
+#define BLSP1_QUP6_I2C_APPS_CLK_SRC				40
+#define BLSP1_UART6_APPS_CLK_SRC				41
+#define BLSP2_QUP1_SPI_APPS_CLK_SRC				42
+#define BLSP2_QUP1_I2C_APPS_CLK_SRC				43
+#define BLSP2_UART1_APPS_CLK_SRC				44
+#define BLSP2_QUP2_SPI_APPS_CLK_SRC				45
+#define BLSP2_QUP2_I2C_APPS_CLK_SRC				46
+#define BLSP2_UART2_APPS_CLK_SRC				47
+#define BLSP2_QUP3_SPI_APPS_CLK_SRC				48
+#define BLSP2_QUP3_I2C_APPS_CLK_SRC				49
+#define BLSP2_UART3_APPS_CLK_SRC				50
+#define BLSP2_QUP4_SPI_APPS_CLK_SRC				51
+#define BLSP2_QUP4_I2C_APPS_CLK_SRC				52
+#define BLSP2_UART4_APPS_CLK_SRC				53
+#define BLSP2_QUP5_SPI_APPS_CLK_SRC				54
+#define BLSP2_QUP5_I2C_APPS_CLK_SRC				55
+#define BLSP2_UART5_APPS_CLK_SRC				56
+#define BLSP2_QUP6_SPI_APPS_CLK_SRC				57
+#define BLSP2_QUP6_I2C_APPS_CLK_SRC				58
+#define BLSP2_UART6_APPS_CLK_SRC				59
+#define PDM2_CLK_SRC						60
+#define TSIF_REF_CLK_SRC					61
+#define CE1_CLK_SRC						62
+#define GCC_SLEEP_CLK_SRC					63
+#define BIMC_CLK_SRC						64
+#define HMSS_AHB_CLK_SRC					65
+#define BIMC_HMSS_AXI_CLK_SRC					66
+#define HMSS_RBCPR_CLK_SRC					67
+#define HMSS_GPLL0_CLK_SRC					68
+#define GP1_CLK_SRC						69
+#define GP2_CLK_SRC						70
+#define GP3_CLK_SRC						71
+#define PCIE_AUX_CLK_SRC					72
+#define UFS_AXI_CLK_SRC						73
+#define UFS_ICE_CORE_CLK_SRC					74
+#define QSPI_SER_CLK_SRC					75
+#define GCC_SYS_NOC_AXI_CLK					76
+#define GCC_SYS_NOC_HMSS_AHB_CLK				77
+#define GCC_SNOC_CNOC_AHB_CLK					78
+#define GCC_SNOC_PNOC_AHB_CLK					79
+#define GCC_SYS_NOC_AT_CLK					80
+#define GCC_SYS_NOC_USB3_AXI_CLK				81
+#define GCC_SYS_NOC_UFS_AXI_CLK					82
+#define GCC_CFG_NOC_AHB_CLK					83
+#define GCC_PERIPH_NOC_AHB_CLK					84
+#define GCC_PERIPH_NOC_USB20_AHB_CLK				85
+#define GCC_TIC_CLK						86
+#define GCC_IMEM_AXI_CLK					87
+#define GCC_MMSS_SYS_NOC_AXI_CLK				88
+#define GCC_MMSS_NOC_CFG_AHB_CLK				89
+#define GCC_MMSS_BIMC_GFX_CLK					90
+#define GCC_USB30_MASTER_CLK					91
+#define GCC_USB30_SLEEP_CLK					92
+#define GCC_USB30_MOCK_UTMI_CLK					93
+#define GCC_USB3_PHY_AUX_CLK					94
+#define GCC_USB3_PHY_PIPE_CLK					95
+#define GCC_USB20_MASTER_CLK					96
+#define GCC_USB20_SLEEP_CLK					97
+#define GCC_USB20_MOCK_UTMI_CLK					98
+#define GCC_USB_PHY_CFG_AHB2PHY_CLK				99
+#define GCC_SDCC1_APPS_CLK					100
+#define GCC_SDCC1_AHB_CLK					101
+#define GCC_SDCC1_ICE_CORE_CLK					102
+#define GCC_SDCC2_APPS_CLK					103
+#define GCC_SDCC2_AHB_CLK					104
+#define GCC_SDCC3_APPS_CLK					105
+#define GCC_SDCC3_AHB_CLK					106
+#define GCC_SDCC4_APPS_CLK					107
+#define GCC_SDCC4_AHB_CLK					108
+#define GCC_BLSP1_AHB_CLK					109
+#define GCC_BLSP1_SLEEP_CLK					110
+#define GCC_BLSP1_QUP1_SPI_APPS_CLK				111
+#define GCC_BLSP1_QUP1_I2C_APPS_CLK				112
+#define GCC_BLSP1_UART1_APPS_CLK				113
+#define GCC_BLSP1_QUP2_SPI_APPS_CLK				114
+#define GCC_BLSP1_QUP2_I2C_APPS_CLK				115
+#define GCC_BLSP1_UART2_APPS_CLK				116
+#define GCC_BLSP1_QUP3_SPI_APPS_CLK				117
+#define GCC_BLSP1_QUP3_I2C_APPS_CLK				118
+#define GCC_BLSP1_UART3_APPS_CLK				119
+#define GCC_BLSP1_QUP4_SPI_APPS_CLK				120
+#define GCC_BLSP1_QUP4_I2C_APPS_CLK				121
+#define GCC_BLSP1_UART4_APPS_CLK				122
+#define GCC_BLSP1_QUP5_SPI_APPS_CLK				123
+#define GCC_BLSP1_QUP5_I2C_APPS_CLK				124
+#define GCC_BLSP1_UART5_APPS_CLK				125
+#define GCC_BLSP1_QUP6_SPI_APPS_CLK				126
+#define GCC_BLSP1_QUP6_I2C_APPS_CLK				127
+#define GCC_BLSP1_UART6_APPS_CLK				128
+#define GCC_BLSP2_AHB_CLK					129
+#define GCC_BLSP2_SLEEP_CLK					130
+#define GCC_BLSP2_QUP1_SPI_APPS_CLK				131
+#define GCC_BLSP2_QUP1_I2C_APPS_CLK				132
+#define GCC_BLSP2_UART1_APPS_CLK				133
+#define GCC_BLSP2_QUP2_SPI_APPS_CLK				134
+#define GCC_BLSP2_QUP2_I2C_APPS_CLK				135
+#define GCC_BLSP2_UART2_APPS_CLK				136
+#define GCC_BLSP2_QUP3_SPI_APPS_CLK				137
+#define GCC_BLSP2_QUP3_I2C_APPS_CLK				138
+#define GCC_BLSP2_UART3_APPS_CLK				139
+#define GCC_BLSP2_QUP4_SPI_APPS_CLK				140
+#define GCC_BLSP2_QUP4_I2C_APPS_CLK				141
+#define GCC_BLSP2_UART4_APPS_CLK				142
+#define GCC_BLSP2_QUP5_SPI_APPS_CLK				143
+#define GCC_BLSP2_QUP5_I2C_APPS_CLK				144
+#define GCC_BLSP2_UART5_APPS_CLK				145
+#define GCC_BLSP2_QUP6_SPI_APPS_CLK				146
+#define GCC_BLSP2_QUP6_I2C_APPS_CLK				147
+#define GCC_BLSP2_UART6_APPS_CLK				148
+#define GCC_PDM_AHB_CLK						149
+#define GCC_PDM_XO4_CLK						150
+#define GCC_PDM2_CLK						151
+#define GCC_PRNG_AHB_CLK					152
+#define GCC_TSIF_AHB_CLK					153
+#define GCC_TSIF_REF_CLK					154
+#define GCC_TSIF_INACTIVITY_TIMERS_CLK				155
+#define GCC_TCSR_AHB_CLK					156
+#define GCC_BOOT_ROM_AHB_CLK					157
+#define GCC_MSG_RAM_AHB_CLK					158
+#define GCC_TLMM_AHB_CLK					159
+#define GCC_TLMM_CLK						160
+#define GCC_MPM_AHB_CLK						161
+#define GCC_SPMI_SER_CLK					162
+#define GCC_SPMI_CNOC_AHB_CLK					163
+#define GCC_CE1_CLK						164
+#define GCC_CE1_AXI_CLK						165
+#define GCC_CE1_AHB_CLK						166
+#define GCC_BIMC_HMSS_AXI_CLK					167
+#define GCC_BIMC_GFX_CLK					168
+#define GCC_HMSS_AHB_CLK					169
+#define GCC_HMSS_SLV_AXI_CLK					170
+#define GCC_HMSS_MSTR_AXI_CLK					171
+#define GCC_HMSS_RBCPR_CLK					172
+#define GCC_GP1_CLK						173
+#define GCC_GP2_CLK						174
+#define GCC_GP3_CLK						175
+#define GCC_PCIE_0_SLV_AXI_CLK					176
+#define GCC_PCIE_0_MSTR_AXI_CLK					177
+#define GCC_PCIE_0_CFG_AHB_CLK					178
+#define GCC_PCIE_0_AUX_CLK					179
+#define GCC_PCIE_0_PIPE_CLK					180
+#define GCC_PCIE_1_SLV_AXI_CLK					181
+#define GCC_PCIE_1_MSTR_AXI_CLK					182
+#define GCC_PCIE_1_CFG_AHB_CLK					183
+#define GCC_PCIE_1_AUX_CLK					184
+#define GCC_PCIE_1_PIPE_CLK					185
+#define GCC_PCIE_2_SLV_AXI_CLK					186
+#define GCC_PCIE_2_MSTR_AXI_CLK					187
+#define GCC_PCIE_2_CFG_AHB_CLK					188
+#define GCC_PCIE_2_AUX_CLK					189
+#define GCC_PCIE_2_PIPE_CLK					190
+#define GCC_PCIE_PHY_CFG_AHB_CLK				191
+#define GCC_PCIE_PHY_AUX_CLK					192
+#define GCC_UFS_AXI_CLK						193
+#define GCC_UFS_AHB_CLK						194
+#define GCC_UFS_TX_CFG_CLK					195
+#define GCC_UFS_RX_CFG_CLK					196
+#define GCC_UFS_TX_SYMBOL_0_CLK					197
+#define GCC_UFS_RX_SYMBOL_0_CLK					198
+#define GCC_UFS_RX_SYMBOL_1_CLK					199
+#define GCC_UFS_UNIPRO_CORE_CLK					200
+#define GCC_UFS_ICE_CORE_CLK					201
+#define GCC_UFS_SYS_CLK_CORE_CLK				202
+#define GCC_UFS_TX_SYMBOL_CLK_CORE_CLK				203
+#define GCC_AGGRE0_SNOC_AXI_CLK					204
+#define GCC_AGGRE0_CNOC_AHB_CLK					205
+#define GCC_SMMU_AGGRE0_AXI_CLK					206
+#define GCC_SMMU_AGGRE0_AHB_CLK					207
+#define GCC_AGGRE1_PNOC_AHB_CLK					208
+#define GCC_AGGRE2_UFS_AXI_CLK					209
+#define GCC_AGGRE2_USB3_AXI_CLK					210
+#define GCC_QSPI_AHB_CLK					211
+#define GCC_QSPI_SER_CLK					212
+#define GCC_USB3_CLKREF_CLK					213
+#define GCC_HDMI_CLKREF_CLK					214
+#define GCC_UFS_CLKREF_CLK					215
+#define GCC_PCIE_CLKREF_CLK					216
+#define GCC_RX2_USB2_CLKREF_CLK					217
+#define GCC_RX1_USB2_CLKREF_CLK					218
+
+#define GCC_SYSTEM_NOC_BCR					0
+#define GCC_CONFIG_NOC_BCR					1
+#define GCC_PERIPH_NOC_BCR					2
+#define GCC_IMEM_BCR						3
+#define GCC_MMSS_BCR						4
+#define GCC_PIMEM_BCR						5
+#define GCC_QDSS_BCR						6
+#define GCC_USB_30_BCR						7
+#define GCC_USB_20_BCR						8
+#define GCC_QUSB2PHY_PRIM_BCR					9
+#define GCC_QUSB2PHY_SEC_BCR					10
+#define GCC_USB_PHY_CFG_AHB2PHY_BCR				11
+#define GCC_SDCC1_BCR						12
+#define GCC_SDCC2_BCR						13
+#define GCC_SDCC3_BCR						14
+#define GCC_SDCC4_BCR						15
+#define GCC_BLSP1_BCR						16
+#define GCC_BLSP1_QUP1_BCR					17
+#define GCC_BLSP1_UART1_BCR					18
+#define GCC_BLSP1_QUP2_BCR					19
+#define GCC_BLSP1_UART2_BCR					20
+#define GCC_BLSP1_QUP3_BCR					21
+#define GCC_BLSP1_UART3_BCR					22
+#define GCC_BLSP1_QUP4_BCR					23
+#define GCC_BLSP1_UART4_BCR					24
+#define GCC_BLSP1_QUP5_BCR					25
+#define GCC_BLSP1_UART5_BCR					26
+#define GCC_BLSP1_QUP6_BCR					27
+#define GCC_BLSP1_UART6_BCR					28
+#define GCC_BLSP2_BCR						29
+#define GCC_BLSP2_QUP1_BCR					30
+#define GCC_BLSP2_UART1_BCR					31
+#define GCC_BLSP2_QUP2_BCR					32
+#define GCC_BLSP2_UART2_BCR					33
+#define GCC_BLSP2_QUP3_BCR					34
+#define GCC_BLSP2_UART3_BCR					35
+#define GCC_BLSP2_QUP4_BCR					36
+#define GCC_BLSP2_UART4_BCR					37
+#define GCC_BLSP2_QUP5_BCR					38
+#define GCC_BLSP2_UART5_BCR					39
+#define GCC_BLSP2_QUP6_BCR					40
+#define GCC_BLSP2_UART6_BCR					41
+#define GCC_PDM_BCR						42
+#define GCC_PRNG_BCR						43
+#define GCC_TSIF_BCR						44
+#define GCC_TCSR_BCR						45
+#define GCC_BOOT_ROM_BCR					46
+#define GCC_MSG_RAM_BCR						47
+#define GCC_TLMM_BCR						48
+#define GCC_MPM_BCR						49
+#define GCC_SEC_CTRL_BCR					50
+#define GCC_SPMI_BCR						51
+#define GCC_SPDM_BCR						52
+#define GCC_CE1_BCR						53
+#define GCC_BIMC_BCR						54
+#define GCC_SNOC_BUS_TIMEOUT0_BCR				55
+#define GCC_SNOC_BUS_TIMEOUT2_BCR				56
+#define GCC_SNOC_BUS_TIMEOUT1_BCR				57
+#define GCC_SNOC_BUS_TIMEOUT3_BCR				58
+#define GCC_SNOC_BUS_TIMEOUT_EXTREF_BCR				59
+#define GCC_PNOC_BUS_TIMEOUT0_BCR				60
+#define GCC_PNOC_BUS_TIMEOUT1_BCR				61
+#define GCC_PNOC_BUS_TIMEOUT2_BCR				62
+#define GCC_PNOC_BUS_TIMEOUT3_BCR				63
+#define GCC_PNOC_BUS_TIMEOUT4_BCR				64
+#define GCC_CNOC_BUS_TIMEOUT0_BCR				65
+#define GCC_CNOC_BUS_TIMEOUT1_BCR				66
+#define GCC_CNOC_BUS_TIMEOUT2_BCR				67
+#define GCC_CNOC_BUS_TIMEOUT3_BCR				68
+#define GCC_CNOC_BUS_TIMEOUT4_BCR				69
+#define GCC_CNOC_BUS_TIMEOUT5_BCR				70
+#define GCC_CNOC_BUS_TIMEOUT6_BCR				71
+#define GCC_CNOC_BUS_TIMEOUT7_BCR				72
+#define GCC_CNOC_BUS_TIMEOUT8_BCR				73
+#define GCC_CNOC_BUS_TIMEOUT9_BCR				74
+#define GCC_CNOC_BUS_TIMEOUT_EXTREF_BCR				75
+#define GCC_APB2JTAG_BCR					76
+#define GCC_RBCPR_CX_BCR					77
+#define GCC_RBCPR_MX_BCR					78
+#define GCC_PCIE_0_BCR						79
+#define GCC_PCIE_0_PHY_BCR					80
+#define GCC_PCIE_1_BCR						81
+#define GCC_PCIE_1_PHY_BCR					82
+#define GCC_PCIE_2_BCR						83
+#define GCC_PCIE_2_PHY_BCR					84
+#define GCC_PCIE_PHY_BCR					85
+#define GCC_DCD_BCR						86
+#define GCC_OBT_ODT_BCR						87
+#define GCC_UFS_BCR						88
+#define GCC_SSC_BCR						89
+#define GCC_VS_BCR						90
+#define GCC_AGGRE0_NOC_BCR					91
+#define GCC_AGGRE1_NOC_BCR					92
+#define GCC_AGGRE2_NOC_BCR					93
+#define GCC_DCC_BCR						94
+#define GCC_IPA_BCR						95
+#define GCC_QSPI_BCR						96
+#define GCC_SKL_BCR						97
+#define GCC_MSMPU_BCR						98
+#define GCC_MSS_Q6_BCR						99
+#define GCC_QREFS_VBG_CAL_BCR					100
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,mmcc-msm8996.h b/include/dt-bindings/clock/qcom,mmcc-msm8996.h
new file mode 100644
index 0000000..9b81ca6
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,mmcc-msm8996.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DT_BINDINGS_CLK_MSM_MMCC_8996_H
+#define _DT_BINDINGS_CLK_MSM_MMCC_8996_H
+
+#define MMPLL0_EARLY					0
+#define MMPLL0_PLL					1
+#define MMPLL1_EARLY					2
+#define MMPLL1_PLL					3
+#define MMPLL2_EARLY					4
+#define MMPLL2_PLL					5
+#define MMPLL3_EARLY					6
+#define MMPLL3_PLL					7
+#define MMPLL4_EARLY					8
+#define MMPLL4_PLL					9
+#define MMPLL5_EARLY					10
+#define MMPLL5_PLL					11
+#define MMPLL8_EARLY					12
+#define MMPLL8_PLL					13
+#define MMPLL9_EARLY					14
+#define MMPLL9_PLL					15
+#define AHB_CLK_SRC					16
+#define AXI_CLK_SRC					17
+#define MAXI_CLK_SRC					18
+#define DSA_CORE_CLK_SRC				19
+#define GFX3D_CLK_SRC					20
+#define RBBMTIMER_CLK_SRC				21
+#define ISENSE_CLK_SRC					22
+#define RBCPR_CLK_SRC					23
+#define VIDEO_CORE_CLK_SRC				24
+#define VIDEO_SUBCORE0_CLK_SRC				25
+#define VIDEO_SUBCORE1_CLK_SRC				26
+#define PCLK0_CLK_SRC					27
+#define PCLK1_CLK_SRC					28
+#define MDP_CLK_SRC					29
+#define EXTPCLK_CLK_SRC					30
+#define VSYNC_CLK_SRC					31
+#define HDMI_CLK_SRC					32
+#define BYTE0_CLK_SRC					33
+#define BYTE1_CLK_SRC					34
+#define ESC0_CLK_SRC					35
+#define ESC1_CLK_SRC					36
+#define CAMSS_GP0_CLK_SRC				37
+#define CAMSS_GP1_CLK_SRC				38
+#define MCLK0_CLK_SRC					39
+#define MCLK1_CLK_SRC					40
+#define MCLK2_CLK_SRC					41
+#define MCLK3_CLK_SRC					42
+#define CCI_CLK_SRC					43
+#define CSI0PHYTIMER_CLK_SRC				44
+#define CSI1PHYTIMER_CLK_SRC				45
+#define CSI2PHYTIMER_CLK_SRC				46
+#define CSIPHY0_3P_CLK_SRC				47
+#define CSIPHY1_3P_CLK_SRC				48
+#define CSIPHY2_3P_CLK_SRC				49
+#define JPEG0_CLK_SRC					50
+#define JPEG2_CLK_SRC					51
+#define JPEG_DMA_CLK_SRC				52
+#define VFE0_CLK_SRC					53
+#define VFE1_CLK_SRC					54
+#define CPP_CLK_SRC					55
+#define CSI0_CLK_SRC					56
+#define CSI1_CLK_SRC					57
+#define CSI2_CLK_SRC					58
+#define CSI3_CLK_SRC					59
+#define FD_CORE_CLK_SRC					60
+#define MMSS_CXO_CLK					61
+#define MMSS_SLEEPCLK_CLK				62
+#define MMSS_MMAGIC_AHB_CLK				63
+#define MMSS_MMAGIC_CFG_AHB_CLK				64
+#define MMSS_MISC_AHB_CLK				65
+#define MMSS_MISC_CXO_CLK				66
+#define MMSS_BTO_AHB_CLK				67
+#define MMSS_MMAGIC_AXI_CLK				68
+#define MMSS_S0_AXI_CLK					69
+#define MMSS_MMAGIC_MAXI_CLK				70
+#define DSA_CORE_CLK					71
+#define DSA_NOC_CFG_AHB_CLK				72
+#define MMAGIC_CAMSS_AXI_CLK				73
+#define MMAGIC_CAMSS_NOC_CFG_AHB_CLK			74
+#define THROTTLE_CAMSS_CXO_CLK				75
+#define THROTTLE_CAMSS_AHB_CLK				76
+#define THROTTLE_CAMSS_AXI_CLK				77
+#define SMMU_VFE_AHB_CLK				78
+#define SMMU_VFE_AXI_CLK				79
+#define SMMU_CPP_AHB_CLK				80
+#define SMMU_CPP_AXI_CLK				81
+#define SMMU_JPEG_AHB_CLK				82
+#define SMMU_JPEG_AXI_CLK				83
+#define MMAGIC_MDSS_AXI_CLK				84
+#define MMAGIC_MDSS_NOC_CFG_AHB_CLK			85
+#define THROTTLE_MDSS_CXO_CLK				86
+#define THROTTLE_MDSS_AHB_CLK				87
+#define THROTTLE_MDSS_AXI_CLK				88
+#define SMMU_ROT_AHB_CLK				89
+#define SMMU_ROT_AXI_CLK				90
+#define SMMU_MDP_AHB_CLK				91
+#define SMMU_MDP_AXI_CLK				92
+#define MMAGIC_VIDEO_AXI_CLK				93
+#define MMAGIC_VIDEO_NOC_CFG_AHB_CLK			94
+#define THROTTLE_VIDEO_CXO_CLK				95
+#define THROTTLE_VIDEO_AHB_CLK				96
+#define THROTTLE_VIDEO_AXI_CLK				97
+#define SMMU_VIDEO_AHB_CLK				98
+#define SMMU_VIDEO_AXI_CLK				99
+#define MMAGIC_BIMC_AXI_CLK				100
+#define MMAGIC_BIMC_NOC_CFG_AHB_CLK			101
+#define GPU_GX_GFX3D_CLK				102
+#define GPU_GX_RBBMTIMER_CLK				103
+#define GPU_AHB_CLK					104
+#define GPU_AON_ISENSE_CLK				105
+#define VMEM_MAXI_CLK					106
+#define VMEM_AHB_CLK					107
+#define MMSS_RBCPR_CLK					108
+#define MMSS_RBCPR_AHB_CLK				109
+#define VIDEO_CORE_CLK					110
+#define VIDEO_AXI_CLK					111
+#define VIDEO_MAXI_CLK					112
+#define VIDEO_AHB_CLK					113
+#define VIDEO_SUBCORE0_CLK				114
+#define VIDEO_SUBCORE1_CLK				115
+#define MDSS_AHB_CLK					116
+#define MDSS_HDMI_AHB_CLK				117
+#define MDSS_AXI_CLK					118
+#define MDSS_PCLK0_CLK					119
+#define MDSS_PCLK1_CLK					120
+#define MDSS_MDP_CLK					121
+#define MDSS_EXTPCLK_CLK				122
+#define MDSS_VSYNC_CLK					123
+#define MDSS_HDMI_CLK					124
+#define MDSS_BYTE0_CLK					125
+#define MDSS_BYTE1_CLK					126
+#define MDSS_ESC0_CLK					127
+#define MDSS_ESC1_CLK					128
+#define CAMSS_TOP_AHB_CLK				129
+#define CAMSS_AHB_CLK					130
+#define CAMSS_MICRO_AHB_CLK				131
+#define CAMSS_GP0_CLK					132
+#define CAMSS_GP1_CLK					133
+#define CAMSS_MCLK0_CLK					134
+#define CAMSS_MCLK1_CLK					135
+#define CAMSS_MCLK2_CLK					136
+#define CAMSS_MCLK3_CLK					137
+#define CAMSS_CCI_CLK					138
+#define CAMSS_CCI_AHB_CLK				139
+#define CAMSS_CSI0PHYTIMER_CLK				140
+#define CAMSS_CSI1PHYTIMER_CLK				141
+#define CAMSS_CSI2PHYTIMER_CLK				142
+#define CAMSS_CSIPHY0_3P_CLK				143
+#define CAMSS_CSIPHY1_3P_CLK				144
+#define CAMSS_CSIPHY2_3P_CLK				145
+#define CAMSS_JPEG0_CLK					146
+#define CAMSS_JPEG2_CLK					147
+#define CAMSS_JPEG_DMA_CLK				148
+#define CAMSS_JPEG_AHB_CLK				149
+#define CAMSS_JPEG_AXI_CLK				150
+#define CAMSS_VFE_AHB_CLK				151
+#define CAMSS_VFE_AXI_CLK				152
+#define CAMSS_VFE0_CLK					153
+#define CAMSS_VFE0_STREAM_CLK				154
+#define CAMSS_VFE0_AHB_CLK				155
+#define CAMSS_VFE1_CLK					156
+#define CAMSS_VFE1_STREAM_CLK				157
+#define CAMSS_VFE1_AHB_CLK				158
+#define CAMSS_CSI_VFE0_CLK				159
+#define CAMSS_CSI_VFE1_CLK				160
+#define CAMSS_CPP_VBIF_AHB_CLK				161
+#define CAMSS_CPP_AXI_CLK				162
+#define CAMSS_CPP_CLK					163
+#define CAMSS_CPP_AHB_CLK				164
+#define CAMSS_CSI0_CLK					165
+#define CAMSS_CSI0_AHB_CLK				166
+#define CAMSS_CSI0PHY_CLK				167
+#define CAMSS_CSI0RDI_CLK				168
+#define CAMSS_CSI0PIX_CLK				169
+#define CAMSS_CSI1_CLK					170
+#define CAMSS_CSI1_AHB_CLK				171
+#define CAMSS_CSI1PHY_CLK				172
+#define CAMSS_CSI1RDI_CLK				173
+#define CAMSS_CSI1PIX_CLK				174
+#define CAMSS_CSI2_CLK					175
+#define CAMSS_CSI2_AHB_CLK				176
+#define CAMSS_CSI2PHY_CLK				177
+#define CAMSS_CSI2RDI_CLK				178
+#define CAMSS_CSI2PIX_CLK				179
+#define CAMSS_CSI3_CLK					180
+#define CAMSS_CSI3_AHB_CLK				181
+#define CAMSS_CSI3PHY_CLK				182
+#define CAMSS_CSI3RDI_CLK				183
+#define CAMSS_CSI3PIX_CLK				184
+#define CAMSS_ISPIF_AHB_CLK				185
+#define FD_CORE_CLK					186
+#define FD_CORE_UAR_CLK					187
+#define FD_AHB_CLK					188
+#define MMSS_SPDM_CSI0_CLK				189
+#define MMSS_SPDM_JPEG_DMA_CLK				190
+#define MMSS_SPDM_CPP_CLK				191
+#define MMSS_SPDM_PCLK0_CLK				192
+#define MMSS_SPDM_AHB_CLK				193
+#define MMSS_SPDM_GFX3D_CLK				194
+#define MMSS_SPDM_PCLK1_CLK				195
+#define MMSS_SPDM_JPEG2_CLK				196
+#define MMSS_SPDM_DEBUG_CLK				197
+#define MMSS_SPDM_VFE1_CLK				198
+#define MMSS_SPDM_VFE0_CLK				199
+#define MMSS_SPDM_VIDEO_CORE_CLK			200
+#define MMSS_SPDM_AXI_CLK				201
+#define MMSS_SPDM_MDP_CLK				202
+#define MMSS_SPDM_JPEG0_CLK				203
+#define MMSS_SPDM_RM_AXI_CLK				204
+#define MMSS_SPDM_RM_MAXI_CLK				205
+
+#define MMAGICAHB_BCR					0
+#define MMAGIC_CFG_BCR					1
+#define MISC_BCR					2
+#define BTO_BCR						3
+#define MMAGICAXI_BCR					4
+#define MMAGICMAXI_BCR					5
+#define DSA_BCR						6
+#define MMAGIC_CAMSS_BCR				7
+#define THROTTLE_CAMSS_BCR				8
+#define SMMU_VFE_BCR					9
+#define SMMU_CPP_BCR					10
+#define SMMU_JPEG_BCR					11
+#define MMAGIC_MDSS_BCR					12
+#define THROTTLE_MDSS_BCR				13
+#define SMMU_ROT_BCR					14
+#define SMMU_MDP_BCR					15
+#define MMAGIC_VIDEO_BCR				16
+#define THROTTLE_VIDEO_BCR				17
+#define SMMU_VIDEO_BCR					18
+#define MMAGIC_BIMC_BCR					19
+#define GPU_GX_BCR					20
+#define GPU_BCR						21
+#define GPU_AON_BCR					22
+#define VMEM_BCR					23
+#define MMSS_RBCPR_BCR					24
+#define VIDEO_BCR					25
+#define MDSS_BCR					26
+#define CAMSS_TOP_BCR					27
+#define CAMSS_AHB_BCR					28
+#define CAMSS_MICRO_BCR					29
+#define CAMSS_CCI_BCR					30
+#define CAMSS_PHY0_BCR					31
+#define CAMSS_PHY1_BCR					32
+#define CAMSS_PHY2_BCR					33
+#define CAMSS_CSIPHY0_3P_BCR				34
+#define CAMSS_CSIPHY1_3P_BCR				35
+#define CAMSS_CSIPHY2_3P_BCR				36
+#define CAMSS_JPEG_BCR					37
+#define CAMSS_VFE_BCR					38
+#define CAMSS_VFE0_BCR					39
+#define CAMSS_VFE1_BCR					40
+#define CAMSS_CSI_VFE0_BCR				41
+#define CAMSS_CSI_VFE1_BCR				42
+#define CAMSS_CPP_TOP_BCR				43
+#define CAMSS_CPP_BCR					44
+#define CAMSS_CSI0_BCR					45
+#define CAMSS_CSI0RDI_BCR				46
+#define CAMSS_CSI0PIX_BCR				47
+#define CAMSS_CSI1_BCR					48
+#define CAMSS_CSI1RDI_BCR				49
+#define CAMSS_CSI1PIX_BCR				50
+#define CAMSS_CSI2_BCR					51
+#define CAMSS_CSI2RDI_BCR				52
+#define CAMSS_CSI2PIX_BCR				53
+#define CAMSS_CSI3_BCR					54
+#define CAMSS_CSI3RDI_BCR				55
+#define CAMSS_CSI3PIX_BCR				56
+#define CAMSS_ISPIF_BCR					57
+#define FD_BCR						58
+#define MMSS_SPDM_RM_BCR				59
+
+#endif
diff --git a/include/dt-bindings/clock/rk3036-cru.h b/include/dt-bindings/clock/rk3036-cru.h
new file mode 100644
index 0000000..ebc7a7b
--- /dev/null
+++ b/include/dt-bindings/clock/rk3036-cru.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3036_H
+#define _DT_BINDINGS_CLK_ROCKCHIP_RK3036_H
+
+/* core clocks */
+#define PLL_APLL		1
+#define PLL_DPLL		2
+#define PLL_GPLL		3
+#define ARMCLK			4
+
+/* sclk gates (special clocks) */
+#define SCLK_GPU		64
+#define SCLK_SPI		65
+#define SCLK_SDMMC		68
+#define SCLK_SDIO		69
+#define SCLK_EMMC		71
+#define SCLK_NANDC		76
+#define SCLK_UART0		77
+#define SCLK_UART1		78
+#define SCLK_UART2		79
+#define SCLK_I2S		82
+#define SCLK_SPDIF		83
+#define SCLK_TIMER0		85
+#define SCLK_TIMER1		86
+#define SCLK_TIMER2		87
+#define SCLK_TIMER3		88
+#define SCLK_OTGPHY0		93
+#define SCLK_LCDC		100
+#define SCLK_HDMI		109
+#define SCLK_HEVC		111
+#define SCLK_I2S_OUT		113
+#define SCLK_SDMMC_DRV		114
+#define SCLK_SDIO_DRV		115
+#define SCLK_EMMC_DRV		117
+#define SCLK_SDMMC_SAMPLE	118
+#define SCLK_SDIO_SAMPLE	119
+#define SCLK_EMMC_SAMPLE	121
+#define SCLK_PVTM_CORE		123
+#define SCLK_PVTM_GPU		124
+#define SCLK_PVTM_VIDEO		125
+#define SCLK_MAC		151
+#define SCLK_MACREF		152
+#define SCLK_SFC		160
+
+/* aclk gates */
+#define ACLK_DMAC2		194
+#define ACLK_LCDC		197
+#define ACLK_VIO		203
+#define ACLK_VCODEC		208
+#define ACLK_CPU		209
+#define ACLK_PERI		210
+
+/* pclk gates */
+#define PCLK_GPIO0		320
+#define PCLK_GPIO1		321
+#define PCLK_GPIO2		322
+#define PCLK_GRF		329
+#define PCLK_I2C0		332
+#define PCLK_I2C1		333
+#define PCLK_I2C2		334
+#define PCLK_SPI		338
+#define PCLK_UART0		341
+#define PCLK_UART1		342
+#define PCLK_UART2		343
+#define PCLK_PWM		350
+#define PCLK_TIMER		353
+#define PCLK_HDMI		360
+#define PCLK_CPU		362
+#define PCLK_PERI		363
+#define PCLK_DDRUPCTL		364
+#define PCLK_WDT		368
+#define PCLK_ACODEC		369
+
+/* hclk gates */
+#define HCLK_OTG0		449
+#define HCLK_OTG1		450
+#define HCLK_NANDC		453
+#define HCLK_SDMMC		456
+#define HCLK_SDIO		457
+#define HCLK_EMMC		459
+#define HCLK_I2S		462
+#define HCLK_LCDC		465
+#define HCLK_ROM		467
+#define HCLK_VIO_BUS		472
+#define HCLK_VCODEC		476
+#define HCLK_CPU		477
+#define HCLK_PERI		478
+
+#define CLK_NR_CLKS		(HCLK_PERI + 1)
+
+/* soft-reset indices */
+#define SRST_CORE0		0
+#define SRST_CORE1		1
+#define SRST_CORE0_DBG		4
+#define SRST_CORE1_DBG		5
+#define SRST_CORE0_POR		8
+#define SRST_CORE1_POR		9
+#define SRST_L2C		12
+#define SRST_TOPDBG		13
+#define SRST_STRC_SYS_A		14
+#define SRST_PD_CORE_NIU	15
+
+#define SRST_TIMER2		16
+#define SRST_CPUSYS_H		17
+#define SRST_AHB2APB_H		19
+#define SRST_TIMER3		20
+#define SRST_INTMEM		21
+#define SRST_ROM		22
+#define SRST_PERI_NIU		23
+#define SRST_I2S		24
+#define SRST_DDR_PLL		25
+#define SRST_GPU_DLL		26
+#define SRST_TIMER0		27
+#define SRST_TIMER1		28
+#define SRST_CORE_DLL		29
+#define SRST_EFUSE_P		30
+#define SRST_ACODEC_P		31
+
+#define SRST_GPIO0		32
+#define SRST_GPIO1		33
+#define SRST_GPIO2		34
+#define SRST_UART0		39
+#define SRST_UART1		40
+#define SRST_UART2		41
+#define SRST_I2C0		43
+#define SRST_I2C1		44
+#define SRST_I2C2		45
+#define SRST_SFC		47
+
+#define SRST_PWM0		48
+#define SRST_DAP		51
+#define SRST_DAP_SYS		52
+#define SRST_GRF		55
+#define SRST_PERIPHSYS_A	57
+#define SRST_PERIPHSYS_H	58
+#define SRST_PERIPHSYS_P	59
+#define SRST_CPU_PERI		61
+#define SRST_EMEM_PERI		62
+#define SRST_USB_PERI		63
+
+#define SRST_DMA2		64
+#define SRST_MAC		66
+#define SRST_NANDC		68
+#define SRST_USBOTG0		69
+#define SRST_OTGC0		71
+#define SRST_USBOTG1		72
+#define SRST_OTGC1		74
+#define SRST_DDRMSCH		79
+
+#define SRST_MMC0		81
+#define SRST_SDIO		82
+#define SRST_EMMC		83
+#define SRST_SPI0		84
+#define SRST_WDT		86
+#define SRST_DDRPHY		88
+#define SRST_DDRPHY_P		89
+#define SRST_DDRCTRL		90
+#define SRST_DDRCTRL_P		91
+
+#define SRST_HDMI_P		96
+#define SRST_VIO_BUS_H		99
+#define SRST_UTMI0		103
+#define SRST_UTMI1		104
+#define SRST_USBPOR		105
+
+#define SRST_VCODEC_A		112
+#define SRST_VCODEC_H		113
+#define SRST_VIO1_A		114
+#define SRST_HEVC		115
+#define SRST_VCODEC_NIU_A	116
+#define SRST_LCDC1_A		117
+#define SRST_LCDC1_H		118
+#define SRST_LCDC1_D		119
+#define SRST_GPU		120
+#define SRST_GPU_NIU_A		122
+
+#define SRST_DBG_P		131
+
+#endif
diff --git a/include/dt-bindings/clock/rk3228-cru.h b/include/dt-bindings/clock/rk3228-cru.h
new file mode 100644
index 0000000..a78dd89
--- /dev/null
+++ b/include/dt-bindings/clock/rk3228-cru.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
+ * Author: Jeffy Chen <jeffy.chen@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3228_H
+#define _DT_BINDINGS_CLK_ROCKCHIP_RK3228_H
+
+/* core clocks */
+#define PLL_APLL		1
+#define PLL_DPLL		2
+#define PLL_CPLL		3
+#define PLL_GPLL		4
+#define ARMCLK			5
+
+/* sclk gates (special clocks) */
+#define SCLK_SPI0		65
+#define SCLK_NANDC		67
+#define SCLK_SDMMC		68
+#define SCLK_SDIO		69
+#define SCLK_EMMC		71
+#define SCLK_UART0		77
+#define SCLK_UART1		78
+#define SCLK_UART2		79
+#define SCLK_I2S0		80
+#define SCLK_I2S1		81
+#define SCLK_I2S2		82
+#define SCLK_SPDIF		83
+#define SCLK_TIMER0		85
+#define SCLK_TIMER1		86
+#define SCLK_TIMER2		87
+#define SCLK_TIMER3		88
+#define SCLK_TIMER4		89
+#define SCLK_TIMER5		90
+#define SCLK_I2S_OUT		113
+#define SCLK_SDMMC_DRV		114
+#define SCLK_SDIO_DRV		115
+#define SCLK_EMMC_DRV		117
+#define SCLK_SDMMC_SAMPLE	118
+#define SCLK_SDIO_SAMPLE	119
+#define SCLK_EMMC_SAMPLE	121
+
+/* aclk gates */
+#define ACLK_DMAC		194
+#define ACLK_PERI		210
+
+/* pclk gates */
+#define PCLK_GPIO0		320
+#define PCLK_GPIO1		321
+#define PCLK_GPIO2		322
+#define PCLK_GPIO3		323
+#define PCLK_GRF		329
+#define PCLK_I2C0		332
+#define PCLK_I2C1		333
+#define PCLK_I2C2		334
+#define PCLK_I2C3		335
+#define PCLK_SPI0		338
+#define PCLK_UART0		341
+#define PCLK_UART1		342
+#define PCLK_UART2		343
+#define PCLK_PWM		350
+#define PCLK_TIMER		353
+#define PCLK_PERI		363
+
+/* hclk gates */
+#define HCLK_NANDC		453
+#define HCLK_SDMMC		456
+#define HCLK_SDIO		457
+#define HCLK_EMMC		459
+#define HCLK_PERI		478
+
+#define CLK_NR_CLKS		(HCLK_PERI + 1)
+
+/* soft-reset indices */
+#define SRST_CORE0_PO		0
+#define SRST_CORE1_PO		1
+#define SRST_CORE2_PO		2
+#define SRST_CORE3_PO		3
+#define SRST_CORE0		4
+#define SRST_CORE1		5
+#define SRST_CORE2		6
+#define SRST_CORE3		7
+#define SRST_CORE0_DBG		8
+#define SRST_CORE1_DBG		9
+#define SRST_CORE2_DBG		10
+#define SRST_CORE3_DBG		11
+#define SRST_TOPDBG		12
+#define SRST_ACLK_CORE		13
+#define SRST_NOC		14
+#define SRST_L2C		15
+
+#define SRST_CPUSYS_H		18
+#define SRST_BUSSYS_H		19
+#define SRST_SPDIF		20
+#define SRST_INTMEM		21
+#define SRST_ROM		22
+#define SRST_OTG_ADP		23
+#define SRST_I2S0		24
+#define SRST_I2S1		25
+#define SRST_I2S2		26
+#define SRST_ACODEC_P		27
+#define SRST_DFIMON		28
+#define SRST_MSCH		29
+#define SRST_EFUSE1024		30
+#define SRST_EFUSE256		31
+
+#define SRST_GPIO0		32
+#define SRST_GPIO1		33
+#define SRST_GPIO2		34
+#define SRST_GPIO3		35
+#define SRST_PERIPH_NOC_A	36
+#define SRST_PERIPH_NOC_BUS_H	37
+#define SRST_PERIPH_NOC_P	38
+#define SRST_UART0		39
+#define SRST_UART1		40
+#define SRST_UART2		41
+#define SRST_PHYNOC		42
+#define SRST_I2C0		43
+#define SRST_I2C1		44
+#define SRST_I2C2		45
+#define SRST_I2C3		46
+
+#define SRST_PWM		48
+#define SRST_A53_GIC		49
+#define SRST_DAP		51
+#define SRST_DAP_NOC		52
+#define SRST_CRYPTO		53
+#define SRST_SGRF		54
+#define SRST_GRF		55
+#define SRST_GMAC		56
+#define SRST_PERIPH_NOC_H	58
+#define SRST_MACPHY		63
+
+#define SRST_DMA		64
+#define SRST_NANDC		68
+#define SRST_USBOTG		69
+#define SRST_OTGC		70
+#define SRST_USBHOST0		71
+#define SRST_HOST_CTRL0		72
+#define SRST_USBHOST1		73
+#define SRST_HOST_CTRL1		74
+#define SRST_USBHOST2		75
+#define SRST_HOST_CTRL2		76
+#define SRST_USBPOR0		77
+#define SRST_USBPOR1		78
+#define SRST_DDRMSCH		79
+
+#define SRST_SMART_CARD		80
+#define SRST_SDMMC		81
+#define SRST_SDIO		82
+#define SRST_EMMC		83
+#define SRST_SPI		84
+#define SRST_TSP_H		85
+#define SRST_TSP		86
+#define SRST_TSADC		87
+#define SRST_DDRPHY		88
+#define SRST_DDRPHY_P		89
+#define SRST_DDRCTRL		90
+#define SRST_DDRCTRL_P		91
+#define SRST_HOST0_ECHI		92
+#define SRST_HOST1_ECHI		93
+#define SRST_HOST2_ECHI		94
+#define SRST_VOP_NOC_A		95
+
+#define SRST_HDMI_P		96
+#define SRST_VIO_ARBI_H		97
+#define SRST_IEP_NOC_A		98
+#define SRST_VIO_NOC_H		99
+#define SRST_VOP_A		100
+#define SRST_VOP_H		101
+#define SRST_VOP_D		102
+#define SRST_UTMI0		103
+#define SRST_UTMI1		104
+#define SRST_UTMI2		105
+#define SRST_UTMI3		106
+#define SRST_RGA		107
+#define SRST_RGA_NOC_A		108
+#define SRST_RGA_A		109
+#define SRST_RGA_H		110
+#define SRST_HDCP_A		111
+
+#define SRST_VPU_A		112
+#define SRST_VPU_H		113
+#define SRST_VPU_NOC_A		116
+#define SRST_VPU_NOC_H		117
+#define SRST_RKVDEC_A		118
+#define SRST_RKVDEC_NOC_A	119
+#define SRST_RKVDEC_H		120
+#define SRST_RKVDEC_NOC_H	121
+#define SRST_RKVDEC_CORE	122
+#define SRST_RKVDEC_CABAC	123
+#define SRST_IEP_A		124
+#define SRST_IEP_H		125
+#define SRST_GPU_A		126
+#define SRST_GPU_NOC_A		127
+
+#define SRST_CORE_DBG		128
+#define SRST_DBG_P		129
+#define SRST_TIMER0		130
+#define SRST_TIMER1		131
+#define SRST_TIMER2		132
+#define SRST_TIMER3		133
+#define SRST_TIMER4		134
+#define SRST_TIMER5		135
+#define SRST_VIO_H2P		136
+#define SRST_HDMIPHY		139
+#define SRST_VDAC		140
+#define SRST_TIMER_6CH_P	141
+
+#endif
diff --git a/include/dt-bindings/clock/rk3288-cru.h b/include/dt-bindings/clock/rk3288-cru.h
index c719aac..9a586e2 100644
--- a/include/dt-bindings/clock/rk3288-cru.h
+++ b/include/dt-bindings/clock/rk3288-cru.h
@@ -86,6 +86,8 @@
 #define SCLK_USBPHY480M_SRC	122
 #define SCLK_PVTM_CORE		123
 #define SCLK_PVTM_GPU		124
+#define SCLK_CRYPTO		125
+#define SCLK_MIPIDSI_24M	126
 
 #define SCLK_MAC		151
 #define SCLK_MACREF_OUT		152
@@ -164,6 +166,8 @@
 #define PCLK_DDRUPCTL1		366
 #define PCLK_PUBL1		367
 #define PCLK_WDT		368
+#define PCLK_EFUSE256		369
+#define PCLK_EFUSE1024		370
 
 /* hclk gates */
 #define HCLK_GPS		448
diff --git a/include/dt-bindings/clock/tegra210-car.h b/include/dt-bindings/clock/tegra210-car.h
new file mode 100644
index 0000000..6f45aea
--- /dev/null
+++ b/include/dt-bindings/clock/tegra210-car.h
@@ -0,0 +1,401 @@
+/*
+ * This header provides constants for binding nvidia,tegra210-car.
+ *
+ * The first 224 clocks are numbered to match the bits in the CAR's CLK_OUT_ENB
+ * registers. These IDs often match those in the CAR's RST_DEVICES registers,
+ * but not in all cases. Some bits in CLK_OUT_ENB affect multiple clocks. In
+ * this case, those clocks are assigned IDs above 224 in order to highlight
+ * this issue. Implementations that interpret these clock IDs as bit values
+ * within the CLK_OUT_ENB or RST_DEVICES registers should be careful to
+ * explicitly handle these special cases.
+ *
+ * The balance of the clocks controlled by the CAR are assigned IDs of 224 and
+ * above.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_TEGRA210_CAR_H
+#define _DT_BINDINGS_CLOCK_TEGRA210_CAR_H
+
+/* 0 */
+/* 1 */
+/* 2 */
+#define TEGRA210_CLK_ISPB 3
+#define TEGRA210_CLK_RTC 4
+#define TEGRA210_CLK_TIMER 5
+#define TEGRA210_CLK_UARTA 6
+/* 7 (register bit affects uartb and vfir) */
+#define TEGRA210_CLK_GPIO 8
+#define TEGRA210_CLK_SDMMC2 9
+/* 10 (register bit affects spdif_in and spdif_out) */
+#define TEGRA210_CLK_I2S1 11
+#define TEGRA210_CLK_I2C1 12
+/* 13 */
+#define TEGRA210_CLK_SDMMC1 14
+#define TEGRA210_CLK_SDMMC4 15
+/* 16 */
+#define TEGRA210_CLK_PWM 17
+#define TEGRA210_CLK_I2S2 18
+/* 19 */
+/* 20 (register bit affects vi and vi_sensor) */
+/* 21 */
+#define TEGRA210_CLK_USBD 22
+#define TEGRA210_CLK_ISP 23
+/* 24 */
+/* 25 */
+#define TEGRA210_CLK_DISP2 26
+#define TEGRA210_CLK_DISP1 27
+#define TEGRA210_CLK_HOST1X 28
+/* 29 */
+#define TEGRA210_CLK_I2S0 30
+/* 31 */
+
+#define TEGRA210_CLK_MC 32
+#define TEGRA210_CLK_AHBDMA 33
+#define TEGRA210_CLK_APBDMA 34
+/* 35 */
+/* 36 */
+/* 37 */
+#define TEGRA210_CLK_PMC 38
+/* 39 (register bit affects fuse and fuse_burn) */
+#define TEGRA210_CLK_KFUSE 40
+#define TEGRA210_CLK_SBC1 41
+/* 42 */
+/* 43 */
+#define TEGRA210_CLK_SBC2 44
+/* 45 */
+#define TEGRA210_CLK_SBC3 46
+#define TEGRA210_CLK_I2C5 47
+#define TEGRA210_CLK_DSIA 48
+/* 49 */
+/* 50 */
+/* 51 */
+#define TEGRA210_CLK_CSI 52
+/* 53 */
+#define TEGRA210_CLK_I2C2 54
+#define TEGRA210_CLK_UARTC 55
+#define TEGRA210_CLK_MIPI_CAL 56
+#define TEGRA210_CLK_EMC 57
+#define TEGRA210_CLK_USB2 58
+/* 59 */
+/* 60 */
+/* 61 */
+/* 62 */
+#define TEGRA210_CLK_BSEV 63
+
+/* 64 */
+#define TEGRA210_CLK_UARTD 65
+/* 66 */
+#define TEGRA210_CLK_I2C3 67
+#define TEGRA210_CLK_SBC4 68
+#define TEGRA210_CLK_SDMMC3 69
+#define TEGRA210_CLK_PCIE 70
+#define TEGRA210_CLK_OWR 71
+#define TEGRA210_CLK_AFI 72
+#define TEGRA210_CLK_CSITE 73
+/* 74 */
+/* 75 */
+/* 76 */
+/* 77 */
+#define TEGRA210_CLK_SOC_THERM 78
+#define TEGRA210_CLK_DTV 79
+/* 80 */
+#define TEGRA210_CLK_I2CSLOW 81
+#define TEGRA210_CLK_DSIB 82
+#define TEGRA210_CLK_TSEC 83
+/* 84 */
+/* 85 */
+/* 86 */
+/* 87 */
+/* 88 */
+#define TEGRA210_CLK_XUSB_HOST 89
+/* 90 */
+/* 91 */
+#define TEGRA210_CLK_CSUS 92
+/* 93 */
+/* 94 */
+/* 95 (bit affects xusb_dev and xusb_dev_src) */
+
+/* 96 */
+/* 97 */
+/* 98 */
+#define TEGRA210_CLK_MSELECT 99
+#define TEGRA210_CLK_TSENSOR 100
+#define TEGRA210_CLK_I2S3 101
+#define TEGRA210_CLK_I2S4 102
+#define TEGRA210_CLK_I2C4 103
+/* 104 */
+/* 105 */
+#define TEGRA210_CLK_D_AUDIO 106
+/* 107 ( affects abp -> ape) */
+/* 108 */
+/* 109 */
+/* 110 */
+#define TEGRA210_CLK_HDA2CODEC_2X 111
+/* 112 */
+/* 113 */
+/* 114 */
+/* 115 */
+/* 116 */
+/* 117 */
+#define TEGRA210_CLK_SPDIF_2X 118
+#define TEGRA210_CLK_ACTMON 119
+#define TEGRA210_CLK_EXTERN1 120
+#define TEGRA210_CLK_EXTERN2 121
+#define TEGRA210_CLK_EXTERN3 122
+#define TEGRA210_CLK_SATA_OOB 123
+#define TEGRA210_CLK_SATA 124
+#define TEGRA210_CLK_HDA 125
+/* 126 */
+/* 127 */
+
+#define TEGRA210_CLK_HDA2HDMI 128
+/* 129 */
+/* 130 */
+/* 131 */
+/* 132 */
+/* 133 */
+/* 134 */
+/* 135 */
+/* 136 */
+/* 137 */
+/* 138 */
+/* 139 */
+/* 140 */
+/* 141 */
+/* 142 */
+/* (bit affects xusb_falcon_src, xusb_fs_src, xusb_host_src and xusb_ss_src) */
+#define TEGRA210_CLK_XUSB_GATE 143
+#define TEGRA210_CLK_CILAB 144
+#define TEGRA210_CLK_CILCD 145
+#define TEGRA210_CLK_CILE 146
+#define TEGRA210_CLK_DSIALP 147
+#define TEGRA210_CLK_DSIBLP 148
+#define TEGRA210_CLK_ENTROPY 149
+/* 150 */
+/* 151 */
+/* 152 */
+/* 153 */
+/* 154 */
+/* 155 (bit affects dfll_ref and dfll_soc) */
+#define TEGRA210_CLK_XUSB_SS 156
+/* 157 */
+/* 158 */
+/* 159 */
+
+/* 160 */
+#define TEGRA210_CLK_DMIC1 161
+#define TEGRA210_CLK_DMIC2 162
+/* 163 */
+/* 164 */
+/* 165 */
+#define TEGRA210_CLK_I2C6 166
+/* 167 */
+/* 168 */
+/* 169 */
+/* 170 */
+#define TEGRA210_CLK_VIM2_CLK 171
+/* 172 */
+#define TEGRA210_CLK_MIPIBIF 173
+/* 174 */
+/* 175 */
+/* 176 */
+#define TEGRA210_CLK_CLK72MHZ 177
+#define TEGRA210_CLK_VIC03 178
+/* 179 */
+/* 180 */
+#define TEGRA210_CLK_DPAUX 181
+#define TEGRA210_CLK_SOR0 182
+#define TEGRA210_CLK_SOR1 183
+#define TEGRA210_CLK_GPU 184
+#define TEGRA210_CLK_DBGAPB 185
+/* 186 */
+#define TEGRA210_CLK_PLL_P_OUT_ADSP 187
+/* 188 */
+#define TEGRA210_CLK_PLL_G_REF 189
+/* 190 */
+/* 191 */
+
+/* 192 */
+#define TEGRA210_CLK_SDMMC_LEGACY 193
+#define TEGRA210_CLK_NVDEC 194
+#define TEGRA210_CLK_NVJPG 195
+/* 196 */
+#define TEGRA210_CLK_DMIC3 197
+#define TEGRA210_CLK_APE 198
+/* 199 */
+/* 200 */
+/* 201 */
+#define TEGRA210_CLK_MAUD 202
+/* 203 */
+/* 204 */
+/* 205 */
+#define TEGRA210_CLK_TSECB 206
+#define TEGRA210_CLK_DPAUX1 207
+#define TEGRA210_CLK_VI_I2C 208
+#define TEGRA210_CLK_HSIC_TRK 209
+#define TEGRA210_CLK_USB2_TRK 210
+#define TEGRA210_CLK_QSPI 211
+#define TEGRA210_CLK_UARTAPE 212
+/* 213 */
+/* 214 */
+/* 215 */
+/* 216 */
+/* 217 */
+/* 218 */
+#define TEGRA210_CLK_NVENC 219
+/* 220 */
+/* 221 */
+#define TEGRA210_CLK_SOR_SAFE 222
+#define TEGRA210_CLK_PLL_P_OUT_CPU 223
+
+
+#define TEGRA210_CLK_UARTB 224
+#define TEGRA210_CLK_VFIR 225
+#define TEGRA210_CLK_SPDIF_IN 226
+#define TEGRA210_CLK_SPDIF_OUT 227
+#define TEGRA210_CLK_VI 228
+#define TEGRA210_CLK_VI_SENSOR 229
+#define TEGRA210_CLK_FUSE 230
+#define TEGRA210_CLK_FUSE_BURN 231
+#define TEGRA210_CLK_CLK_32K 232
+#define TEGRA210_CLK_CLK_M 233
+#define TEGRA210_CLK_CLK_M_DIV2 234
+#define TEGRA210_CLK_CLK_M_DIV4 235
+#define TEGRA210_CLK_PLL_REF 236
+#define TEGRA210_CLK_PLL_C 237
+#define TEGRA210_CLK_PLL_C_OUT1 238
+#define TEGRA210_CLK_PLL_C2 239
+#define TEGRA210_CLK_PLL_C3 240
+#define TEGRA210_CLK_PLL_M 241
+#define TEGRA210_CLK_PLL_M_OUT1 242
+#define TEGRA210_CLK_PLL_P 243
+#define TEGRA210_CLK_PLL_P_OUT1 244
+#define TEGRA210_CLK_PLL_P_OUT2 245
+#define TEGRA210_CLK_PLL_P_OUT3 246
+#define TEGRA210_CLK_PLL_P_OUT4 247
+#define TEGRA210_CLK_PLL_A 248
+#define TEGRA210_CLK_PLL_A_OUT0 249
+#define TEGRA210_CLK_PLL_D 250
+#define TEGRA210_CLK_PLL_D_OUT0 251
+#define TEGRA210_CLK_PLL_D2 252
+#define TEGRA210_CLK_PLL_D2_OUT0 253
+#define TEGRA210_CLK_PLL_U 254
+#define TEGRA210_CLK_PLL_U_480M 255
+
+#define TEGRA210_CLK_PLL_U_60M 256
+#define TEGRA210_CLK_PLL_U_48M 257
+/* 258 */
+#define TEGRA210_CLK_PLL_X 259
+#define TEGRA210_CLK_PLL_X_OUT0 260
+#define TEGRA210_CLK_PLL_RE_VCO 261
+#define TEGRA210_CLK_PLL_RE_OUT 262
+#define TEGRA210_CLK_PLL_E 263
+#define TEGRA210_CLK_SPDIF_IN_SYNC 264
+#define TEGRA210_CLK_I2S0_SYNC 265
+#define TEGRA210_CLK_I2S1_SYNC 266
+#define TEGRA210_CLK_I2S2_SYNC 267
+#define TEGRA210_CLK_I2S3_SYNC 268
+#define TEGRA210_CLK_I2S4_SYNC 269
+#define TEGRA210_CLK_VIMCLK_SYNC 270
+#define TEGRA210_CLK_AUDIO0 271
+#define TEGRA210_CLK_AUDIO1 272
+#define TEGRA210_CLK_AUDIO2 273
+#define TEGRA210_CLK_AUDIO3 274
+#define TEGRA210_CLK_AUDIO4 275
+#define TEGRA210_CLK_SPDIF 276
+#define TEGRA210_CLK_CLK_OUT_1 277
+#define TEGRA210_CLK_CLK_OUT_2 278
+#define TEGRA210_CLK_CLK_OUT_3 279
+#define TEGRA210_CLK_BLINK 280
+/* 281 */
+/* 282 */
+/* 283 */
+#define TEGRA210_CLK_XUSB_HOST_SRC 284
+#define TEGRA210_CLK_XUSB_FALCON_SRC 285
+#define TEGRA210_CLK_XUSB_FS_SRC 286
+#define TEGRA210_CLK_XUSB_SS_SRC 287
+
+#define TEGRA210_CLK_XUSB_DEV_SRC 288
+#define TEGRA210_CLK_XUSB_DEV 289
+#define TEGRA210_CLK_XUSB_HS_SRC 290
+#define TEGRA210_CLK_SCLK 291
+#define TEGRA210_CLK_HCLK 292
+#define TEGRA210_CLK_PCLK 293
+#define TEGRA210_CLK_CCLK_G 294
+#define TEGRA210_CLK_CCLK_LP 295
+#define TEGRA210_CLK_DFLL_REF 296
+#define TEGRA210_CLK_DFLL_SOC 297
+#define TEGRA210_CLK_VI_SENSOR2 298
+#define TEGRA210_CLK_PLL_P_OUT5 299
+#define TEGRA210_CLK_CML0 300
+#define TEGRA210_CLK_CML1 301
+#define TEGRA210_CLK_PLL_C4 302
+#define TEGRA210_CLK_PLL_DP 303
+#define TEGRA210_CLK_PLL_E_MUX 304
+#define TEGRA210_CLK_PLL_MB 305
+#define TEGRA210_CLK_PLL_A1 306
+#define TEGRA210_CLK_PLL_D_DSI_OUT 307
+#define TEGRA210_CLK_PLL_C4_OUT0 308
+#define TEGRA210_CLK_PLL_C4_OUT1 309
+#define TEGRA210_CLK_PLL_C4_OUT2 310
+#define TEGRA210_CLK_PLL_C4_OUT3 311
+#define TEGRA210_CLK_PLL_U_OUT 312
+#define TEGRA210_CLK_PLL_U_OUT1 313
+#define TEGRA210_CLK_PLL_U_OUT2 314
+#define TEGRA210_CLK_USB2_HSIC_TRK 315
+#define TEGRA210_CLK_PLL_P_OUT_HSIO 316
+#define TEGRA210_CLK_PLL_P_OUT_XUSB 317
+#define TEGRA210_CLK_XUSB_SSP_SRC 318
+/* 319 */
+/* 320 */
+/* 321 */
+/* 322 */
+/* 323 */
+/* 324 */
+/* 325 */
+/* 326 */
+/* 327 */
+/* 328 */
+/* 329 */
+/* 330 */
+/* 331 */
+/* 332 */
+/* 333 */
+/* 334 */
+/* 335 */
+/* 336 */
+/* 337 */
+/* 338 */
+/* 339 */
+/* 340 */
+/* 341 */
+/* 342 */
+/* 343 */
+/* 344 */
+/* 345 */
+/* 346 */
+/* 347 */
+/* 348 */
+/* 349 */
+
+#define TEGRA210_CLK_AUDIO0_MUX 350
+#define TEGRA210_CLK_AUDIO1_MUX 351
+#define TEGRA210_CLK_AUDIO2_MUX 352
+#define TEGRA210_CLK_AUDIO3_MUX 353
+#define TEGRA210_CLK_AUDIO4_MUX 354
+#define TEGRA210_CLK_SPDIF_MUX 355
+#define TEGRA210_CLK_CLK_OUT_1_MUX 356
+#define TEGRA210_CLK_CLK_OUT_2_MUX 357
+#define TEGRA210_CLK_CLK_OUT_3_MUX 358
+#define TEGRA210_CLK_DSIA_MUX 359
+#define TEGRA210_CLK_DSIB_MUX 360
+#define TEGRA210_CLK_SOR0_LVDS 361
+#define TEGRA210_CLK_XUSB_SS_DIV2 362
+
+#define TEGRA210_CLK_PLL_M_UD 363
+#define TEGRA210_CLK_PLL_C_UD 364
+#define TEGRA210_CLK_SCLK_MUX 365
+
+#define TEGRA210_CLK_CLK_MAX 366
+
+#endif	/* _DT_BINDINGS_CLOCK_TEGRA210_CAR_H */
diff --git a/include/linux/basic_mmio_gpio.h b/include/linux/basic_mmio_gpio.h
deleted file mode 100644
index ed3768f..0000000
--- a/include/linux/basic_mmio_gpio.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Basic memory-mapped GPIO controllers.
- *
- * Copyright 2008 MontaVista Software, Inc.
- * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#ifndef __BASIC_MMIO_GPIO_H
-#define __BASIC_MMIO_GPIO_H
-
-#include <linux/gpio.h>
-#include <linux/types.h>
-#include <linux/compiler.h>
-#include <linux/spinlock_types.h>
-
-struct bgpio_pdata {
-	const char *label;
-	int base;
-	int ngpio;
-};
-
-struct device;
-
-struct bgpio_chip {
-	struct gpio_chip gc;
-
-	unsigned long (*read_reg)(void __iomem *reg);
-	void (*write_reg)(void __iomem *reg, unsigned long data);
-
-	void __iomem *reg_dat;
-	void __iomem *reg_set;
-	void __iomem *reg_clr;
-	void __iomem *reg_dir;
-
-	/* Number of bits (GPIOs): <register width> * 8. */
-	int bits;
-
-	/*
-	 * Some GPIO controllers work with the big-endian bits notation,
-	 * e.g. in a 8-bits register, GPIO7 is the least significant bit.
-	 */
-	unsigned long (*pin2mask)(struct bgpio_chip *bgc, unsigned int pin);
-
-	/*
-	 * Used to lock bgpio_chip->data. Also, this is needed to keep
-	 * shadowed and real data registers writes together.
-	 */
-	spinlock_t lock;
-
-	/* Shadowed data register to clear/set bits safely. */
-	unsigned long data;
-
-	/* Shadowed direction registers to clear/set direction safely. */
-	unsigned long dir;
-};
-
-static inline struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc)
-{
-	return container_of(gc, struct bgpio_chip, gc);
-}
-
-int bgpio_remove(struct bgpio_chip *bgc);
-int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
-	       unsigned long sz, void __iomem *dat, void __iomem *set,
-	       void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
-	       unsigned long flags);
-
-#define BGPIOF_BIG_ENDIAN		BIT(0)
-#define BGPIOF_UNREADABLE_REG_SET	BIT(1) /* reg_set is unreadable */
-#define BGPIOF_UNREADABLE_REG_DIR	BIT(2) /* reg_dir is unreadable */
-#define BGPIOF_BIG_ENDIAN_BYTE_ORDER	BIT(3)
-#define BGPIOF_READ_OUTPUT_REG_SET     BIT(4) /* reg_set stores output value */
-#define BGPIOF_NO_OUTPUT		BIT(5) /* only input */
-
-#endif /* __BASIC_MMIO_GPIO_H */
diff --git a/include/linux/bcm47xx_wdt.h b/include/linux/bcm47xx_wdt.h
index 5582c21..8d9d07e 100644
--- a/include/linux/bcm47xx_wdt.h
+++ b/include/linux/bcm47xx_wdt.h
@@ -1,7 +1,6 @@
 #ifndef LINUX_BCM47XX_WDT_H_
 #define LINUX_BCM47XX_WDT_H_
 
-#include <linux/notifier.h>
 #include <linux/timer.h>
 #include <linux/types.h>
 #include <linux/watchdog.h>
@@ -15,8 +14,6 @@
 	void *driver_data;
 
 	struct watchdog_device wdd;
-	struct notifier_block notifier;
-	struct notifier_block restart_handler;
 
 	struct timer_list soft_timer;
 	atomic_t soft_ticks;
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index c56988a..1143e38 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -31,6 +31,7 @@
 #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
 #define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
 #define CLK_RECALC_NEW_RATES	BIT(9) /* recalc rates after notifications */
+#define CLK_SET_RATE_UNGATE	BIT(10) /* clock needs to run to set rate */
 
 struct clk;
 struct clk_hw;
@@ -44,7 +45,7 @@
  * @rate:		Requested clock rate. This field will be adjusted by
  *			clock drivers according to hardware capabilities.
  * @min_rate:		Minimum rate imposed by clk users.
- * @max_rate:		Maximum rate a imposed by clk users.
+ * @max_rate:		Maximum rate imposed by clk users.
  * @best_parent_rate:	The best parent rate a parent can provide to fulfill the
  *			requested constraints.
  * @best_parent_hw:	The most appropriate parent clock that fulfills the
@@ -715,8 +716,7 @@
 {
 	return 0;
 }
-#define of_clk_del_provider(np) \
-	{ while (0); }
+static inline void of_clk_del_provider(struct device_node *np) {}
 static inline struct clk *of_clk_src_simple_get(
 	struct of_phandle_args *clkspec, void *data)
 {
@@ -741,8 +741,7 @@
 {
 	return NULL;
 }
-#define of_clk_init(matches) \
-	{ while (0); }
+static inline void of_clk_init(const struct of_device_id *matches) {}
 #endif /* CONFIG_OF */
 
 /*
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h
index 223be69..75205df 100644
--- a/include/linux/clk/ti.h
+++ b/include/linux/clk/ti.h
@@ -286,6 +286,7 @@
 #define TI_CLK_DPLL_HAS_FREQSEL			BIT(0)
 #define TI_CLK_DPLL4_DENY_REPROGRAM		BIT(1)
 #define TI_CLK_DISABLE_CLKDM_CONTROL		BIT(2)
+#define TI_CLK_ERRATA_I810			BIT(3)
 
 void ti_clk_setup_features(struct ti_clk_features *features);
 const struct ti_clk_features *ti_clk_get_features(void);
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index 5055ac3..5e9c74c 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -22,6 +22,7 @@
 	DMI_DEV_TYPE_IPMI = -1,
 	DMI_DEV_TYPE_OEM_STRING = -2,
 	DMI_DEV_TYPE_DEV_ONBOARD = -3,
+	DMI_DEV_TYPE_DEV_SLOT = -4,
 };
 
 enum dmi_entry_type {
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index d1baebf..82fda48 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -8,6 +8,7 @@
 #include <linux/irqdomain.h>
 #include <linux/lockdep.h>
 #include <linux/pinctrl/pinctrl.h>
+#include <linux/kconfig.h>
 
 struct device;
 struct gpio_desc;
@@ -20,9 +21,10 @@
 /**
  * struct gpio_chip - abstract a GPIO controller
  * @label: for diagnostics
- * @dev: optional device providing the GPIOs
+ * @parent: optional parent device providing the GPIOs
  * @cdev: class device used by sysfs interface (may be NULL)
  * @owner: helps prevent removal of modules exporting active GPIOs
+ * @data: per-instance data assigned by the driver
  * @list: links gpio_chips together for traversal
  * @request: optional hook for chip-specific activation, such as
  *	enabling module power and clock; may sleep
@@ -32,8 +34,7 @@
  *	(same as GPIOF_DIR_XXX), or negative error
  * @direction_input: configures signal "offset" as input, or returns error
  * @direction_output: configures signal "offset" as output, or returns error
- * @get: returns value for signal "offset"; for output signals this
- *	returns either the value actually sensed, or zero
+ * @get: returns value for signal "offset", 0=low, 1=high, or negative error
  * @set: assigns output value for signal "offset"
  * @set_multiple: assigns output values for multiple signals defined by "mask"
  * @set_debounce: optional hook for setting debounce time for specified gpio in
@@ -65,6 +66,23 @@
  *	registers.
  * @irq_not_threaded: flag must be set if @can_sleep is set but the
  *	IRQs don't need to be threaded
+ * @read_reg: reader function for generic GPIO
+ * @write_reg: writer function for generic GPIO
+ * @pin2mask: some generic GPIO controllers work with the big-endian bits
+ *	notation, e.g. in a 8-bits register, GPIO7 is the least significant
+ *	bit. This callback assigns the right bit mask.
+ * @reg_dat: data (in) register for generic GPIO
+ * @reg_set: output set register (out=high) for generic GPIO
+ * @reg_clk: output clear register (out=low) for generic GPIO
+ * @reg_dir: direction setting register for generic GPIO
+ * @bgpio_bits: number of register bits used for a generic GPIO i.e.
+ *	<register width> * 8
+ * @bgpio_lock: used to lock chip->bgpio_data. Also, this is needed to keep
+ *	shadowed and real data registers writes together.
+ * @bgpio_data:	shadowed data register for generic GPIO to clear/set bits
+ *	safely.
+ * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
+ *	direction safely.
  * @irqchip: GPIO IRQ chip impl, provided by GPIO driver
  * @irqdomain: Interrupt translation domain; responsible for mapping
  *	between GPIO hwirq number and linux irq number
@@ -89,9 +107,10 @@
  */
 struct gpio_chip {
 	const char		*label;
-	struct device		*dev;
+	struct device		*parent;
 	struct device		*cdev;
 	struct module		*owner;
+	void			*data;
 	struct list_head        list;
 
 	int			(*request)(struct gpio_chip *chip,
@@ -127,6 +146,20 @@
 	bool			can_sleep;
 	bool			irq_not_threaded;
 
+#if IS_ENABLED(CONFIG_GPIO_GENERIC)
+	unsigned long (*read_reg)(void __iomem *reg);
+	void (*write_reg)(void __iomem *reg, unsigned long data);
+	unsigned long (*pin2mask)(struct gpio_chip *gc, unsigned int pin);
+	void __iomem *reg_dat;
+	void __iomem *reg_set;
+	void __iomem *reg_clr;
+	void __iomem *reg_dir;
+	int bgpio_bits;
+	spinlock_t bgpio_lock;
+	unsigned long bgpio_data;
+	unsigned long bgpio_dir;
+#endif
+
 #ifdef CONFIG_GPIOLIB_IRQCHIP
 	/*
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
@@ -166,7 +199,11 @@
 			unsigned offset);
 
 /* add/remove chips */
-extern int gpiochip_add(struct gpio_chip *chip);
+extern int gpiochip_add_data(struct gpio_chip *chip, void *data);
+static inline int gpiochip_add(struct gpio_chip *chip)
+{
+	return gpiochip_add_data(chip, NULL);
+}
 extern void gpiochip_remove(struct gpio_chip *chip);
 extern struct gpio_chip *gpiochip_find(void *data,
 			      int (*match)(struct gpio_chip *chip, void *data));
@@ -175,8 +212,36 @@
 int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset);
 void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset);
 
+/* get driver data */
+static inline void *gpiochip_get_data(struct gpio_chip *chip)
+{
+	return chip->data;
+}
+
 struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
 
+struct bgpio_pdata {
+	const char *label;
+	int base;
+	int ngpio;
+};
+
+#if IS_ENABLED(CONFIG_GPIO_GENERIC)
+
+int bgpio_init(struct gpio_chip *gc, struct device *dev,
+	       unsigned long sz, void __iomem *dat, void __iomem *set,
+	       void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
+	       unsigned long flags);
+
+#define BGPIOF_BIG_ENDIAN		BIT(0)
+#define BGPIOF_UNREADABLE_REG_SET	BIT(1) /* reg_set is unreadable */
+#define BGPIOF_UNREADABLE_REG_DIR	BIT(2) /* reg_dir is unreadable */
+#define BGPIOF_BIG_ENDIAN_BYTE_ORDER	BIT(3)
+#define BGPIOF_READ_OUTPUT_REG_SET	BIT(4) /* reg_set stores output value */
+#define BGPIOF_NO_OUTPUT		BIT(5) /* only input */
+
+#endif
+
 #ifdef CONFIG_GPIOLIB_IRQCHIP
 
 void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index 87d6d16..092186c 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -51,8 +51,14 @@
 extern int of_get_named_gpio_flags(struct device_node *np,
 		const char *list_name, int index, enum of_gpio_flags *flags);
 
-extern int of_mm_gpiochip_add(struct device_node *np,
-			      struct of_mm_gpio_chip *mm_gc);
+extern int of_mm_gpiochip_add_data(struct device_node *np,
+				   struct of_mm_gpio_chip *mm_gc,
+				   void *data);
+static inline int of_mm_gpiochip_add(struct device_node *np,
+				     struct of_mm_gpio_chip *mm_gc)
+{
+	return of_mm_gpiochip_add_data(np, mm_gc, NULL);
+}
 extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
 
 extern int of_gpiochip_add(struct gpio_chip *gc);
@@ -67,6 +73,9 @@
 static inline int of_get_named_gpio_flags(struct device_node *np,
 		const char *list_name, int index, enum of_gpio_flags *flags)
 {
+	if (flags)
+		*flags = 0;
+
 	return -ENOSYS;
 }
 
diff --git a/include/linux/platform_data/asoc-s3c.h b/include/linux/platform_data/asoc-s3c.h
index 5e0bc77..15bf56e 100644
--- a/include/linux/platform_data/asoc-s3c.h
+++ b/include/linux/platform_data/asoc-s3c.h
@@ -13,6 +13,9 @@
  */
 #define S3C64XX_AC97_GPD  0
 #define S3C64XX_AC97_GPE  1
+
+#include <linux/dmaengine.h>
+
 extern void s3c64xx_ac97_setup_gpio(int);
 
 struct samsung_i2s {
@@ -39,6 +42,11 @@
  */
 struct s3c_audio_pdata {
 	int (*cfg_gpio)(struct platform_device *);
+	dma_filter_fn dma_filter;
+	void *dma_playback;
+	void *dma_capture;
+	void *dma_play_sec;
+	void *dma_capture_mic;
 	union {
 		struct samsung_i2s i2s;
 	} type;
diff --git a/include/linux/platform_data/gpio-rcar.h b/include/linux/platform_data/gpio-rcar.h
deleted file mode 100644
index 2d8d694..0000000
--- a/include/linux/platform_data/gpio-rcar.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Renesas R-Car GPIO Support
- *
- *  Copyright (C) 2013 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * 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 __GPIO_RCAR_H__
-#define __GPIO_RCAR_H__
-
-struct gpio_rcar_config {
-	int gpio_base;
-	unsigned int irq_base;
-	unsigned int number_of_pins;
-	const char *pctl_name;
-	unsigned has_both_edge_trigger:1;
-};
-
-#define RCAR_GP_PIN(bank, pin)		(((bank) * 32) + (pin))
-
-#endif /* __GPIO_RCAR_H__ */
diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h
index 027b1f4..b585fa2 100644
--- a/include/linux/watchdog.h
+++ b/include/linux/watchdog.h
@@ -12,10 +12,12 @@
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/cdev.h>
+#include <linux/notifier.h>
 #include <uapi/linux/watchdog.h>
 
 struct watchdog_ops;
 struct watchdog_device;
+struct watchdog_core_data;
 
 /** struct watchdog_ops - The watchdog-devices operations
  *
@@ -26,8 +28,7 @@
  * @status:	The routine that shows the status of the watchdog device.
  * @set_timeout:The routine for setting the watchdog devices timeout value (in seconds).
  * @get_timeleft:The routine that gets the time left before a reset (in seconds).
- * @ref:	The ref operation for dyn. allocated watchdog_device structs
- * @unref:	The unref operation for dyn. allocated watchdog_device structs
+ * @restart:	The routine for restarting the machine.
  * @ioctl:	The routines that handles extra ioctl calls.
  *
  * The watchdog_ops structure contains a list of low-level operations
@@ -45,25 +46,26 @@
 	unsigned int (*status)(struct watchdog_device *);
 	int (*set_timeout)(struct watchdog_device *, unsigned int);
 	unsigned int (*get_timeleft)(struct watchdog_device *);
-	void (*ref)(struct watchdog_device *);
-	void (*unref)(struct watchdog_device *);
+	int (*restart)(struct watchdog_device *);
 	long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
 };
 
 /** struct watchdog_device - The structure that defines a watchdog device
  *
  * @id:		The watchdog's ID. (Allocated by watchdog_register_device)
- * @cdev:	The watchdog's Character device.
- * @dev:	The device for our watchdog
  * @parent:	The parent bus device
+ * @groups:	List of sysfs attribute groups to create when creating the
+ *		watchdog device.
  * @info:	Pointer to a watchdog_info structure.
  * @ops:	Pointer to the list of watchdog operations.
  * @bootstatus:	Status of the watchdog device at boot.
  * @timeout:	The watchdog devices timeout value (in seconds).
  * @min_timeout:The watchdog devices minimum timeout value (in seconds).
  * @max_timeout:The watchdog devices maximum timeout value (in seconds).
- * @driver-data:Pointer to the drivers private data.
- * @lock:	Lock for watchdog core internal use only.
+ * @reboot_nb:	The notifier block to stop watchdog on reboot.
+ * @restart_nb:	The notifier block to register a restart function.
+ * @driver_data:Pointer to the drivers private data.
+ * @wd_data:	Pointer to watchdog core internal data.
  * @status:	Field that contains the devices internal status bits.
  * @deferred: entry in wtd_deferred_reg_list which is used to
  *			   register early initialized watchdogs.
@@ -79,24 +81,23 @@
  */
 struct watchdog_device {
 	int id;
-	struct cdev cdev;
-	struct device *dev;
 	struct device *parent;
+	const struct attribute_group **groups;
 	const struct watchdog_info *info;
 	const struct watchdog_ops *ops;
 	unsigned int bootstatus;
 	unsigned int timeout;
 	unsigned int min_timeout;
 	unsigned int max_timeout;
+	struct notifier_block reboot_nb;
+	struct notifier_block restart_nb;
 	void *driver_data;
-	struct mutex lock;
+	struct watchdog_core_data *wd_data;
 	unsigned long status;
 /* Bit numbers for status flags */
 #define WDOG_ACTIVE		0	/* Is the watchdog running/active */
-#define WDOG_DEV_OPEN		1	/* Opened via /dev/watchdog ? */
-#define WDOG_ALLOW_RELEASE	2	/* Did we receive the magic char ? */
-#define WDOG_NO_WAY_OUT		3	/* Is 'nowayout' feature set ? */
-#define WDOG_UNREGISTERED	4	/* Has the device been unregistered */
+#define WDOG_NO_WAY_OUT		1	/* Is 'nowayout' feature set ? */
+#define WDOG_STOP_ON_REBOOT	2	/* Should be stopped on reboot */
 	struct list_head deferred;
 };
 
@@ -116,6 +117,12 @@
 		set_bit(WDOG_NO_WAY_OUT, &wdd->status);
 }
 
+/* Use the following function to stop the watchdog on reboot */
+static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd)
+{
+	set_bit(WDOG_STOP_ON_REBOOT, &wdd->status);
+}
+
 /* Use the following function to check if a timeout value is invalid */
 static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigned int t)
 {
@@ -142,6 +149,7 @@
 }
 
 /* drivers/watchdog/watchdog_core.c */
+void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority);
 extern int watchdog_init_timeout(struct watchdog_device *wdd,
 				  unsigned int timeout_parm, struct device *dev);
 extern int watchdog_register_device(struct watchdog_device *);
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 74bc8547..15aa5f0 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -417,11 +417,13 @@
 #define AC97_RATES_MIC_ADC	4
 #define AC97_RATES_SPDIF	5
 
+#define AC97_NUM_GPIOS		16
 /*
  *
  */
 
 struct snd_ac97;
+struct snd_ac97_gpio_priv;
 struct snd_pcm_chmap;
 
 struct snd_ac97_build_ops {
@@ -529,6 +531,7 @@
 	struct delayed_work power_work;
 #endif
 	struct device dev;
+	struct snd_ac97_gpio_priv *gpio_priv;
 
 	struct snd_pcm_chmap *chmaps[2]; /* channel-maps (optional) */
 };
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h
index fa1d055..c0abcdc 100644
--- a/include/sound/compress_driver.h
+++ b/include/sound/compress_driver.h
@@ -152,13 +152,18 @@
 	unsigned int direction;
 	struct mutex lock;
 	int device;
+#ifdef CONFIG_SND_VERBOSE_PROCFS
+	char id[64];
+	struct snd_info_entry *proc_root;
+	struct snd_info_entry *proc_info_entry;
+#endif
 };
 
 /* compress device register APIs */
 int snd_compress_register(struct snd_compr *device);
 int snd_compress_deregister(struct snd_compr *device);
 int snd_compress_new(struct snd_card *card, int device,
-			int type, struct snd_compr *compr);
+			int type, const char *id, struct snd_compr *compr);
 
 /* dsp driver callback apis
  * For playback: driver should call snd_compress_fragment_elapsed() to let the
diff --git a/include/sound/core.h b/include/sound/core.h
index cdfecaf..31079ea 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -99,6 +99,7 @@
 	char driver[16];		/* driver name */
 	char shortname[32];		/* short name of this soundcard */
 	char longname[80];		/* name of this soundcard */
+	char irq_descr[32];		/* Interrupt description */
 	char mixername[80];		/* mixer name */
 	char components[128];		/* card components delimited with
 								space */
diff --git a/include/sound/da7218.h b/include/sound/da7218.h
new file mode 100644
index 0000000..0dbb818
--- /dev/null
+++ b/include/sound/da7218.h
@@ -0,0 +1,109 @@
+/*
+ * da7218.h - DA7218 ASoC Codec Driver Platform Data
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _DA7218_PDATA_H
+#define _DA7218_PDATA_H
+
+/* Mic Bias */
+enum da7218_micbias_voltage {
+	DA7218_MICBIAS_1_2V = -1,
+	DA7218_MICBIAS_1_6V,
+	DA7218_MICBIAS_1_8V,
+	DA7218_MICBIAS_2_0V,
+	DA7218_MICBIAS_2_2V,
+	DA7218_MICBIAS_2_4V,
+	DA7218_MICBIAS_2_6V,
+	DA7218_MICBIAS_2_8V,
+	DA7218_MICBIAS_3_0V,
+};
+
+enum da7218_mic_amp_in_sel {
+	DA7218_MIC_AMP_IN_SEL_DIFF = 0,
+	DA7218_MIC_AMP_IN_SEL_SE_P,
+	DA7218_MIC_AMP_IN_SEL_SE_N,
+};
+
+/* DMIC */
+enum da7218_dmic_data_sel {
+	DA7218_DMIC_DATA_LRISE_RFALL = 0,
+	DA7218_DMIC_DATA_LFALL_RRISE,
+};
+
+enum da7218_dmic_samplephase {
+	DA7218_DMIC_SAMPLE_ON_CLKEDGE = 0,
+	DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE,
+};
+
+enum da7218_dmic_clk_rate {
+	DA7218_DMIC_CLK_3_0MHZ = 0,
+	DA7218_DMIC_CLK_1_5MHZ,
+};
+
+/* Headphone Detect */
+enum da7218_hpldet_jack_rate {
+	DA7218_HPLDET_JACK_RATE_5US = 0,
+	DA7218_HPLDET_JACK_RATE_10US,
+	DA7218_HPLDET_JACK_RATE_20US,
+	DA7218_HPLDET_JACK_RATE_40US,
+	DA7218_HPLDET_JACK_RATE_80US,
+	DA7218_HPLDET_JACK_RATE_160US,
+	DA7218_HPLDET_JACK_RATE_320US,
+	DA7218_HPLDET_JACK_RATE_640US,
+};
+
+enum da7218_hpldet_jack_debounce {
+	DA7218_HPLDET_JACK_DEBOUNCE_OFF = 0,
+	DA7218_HPLDET_JACK_DEBOUNCE_2,
+	DA7218_HPLDET_JACK_DEBOUNCE_3,
+	DA7218_HPLDET_JACK_DEBOUNCE_4,
+};
+
+enum da7218_hpldet_jack_thr {
+	DA7218_HPLDET_JACK_THR_84PCT = 0,
+	DA7218_HPLDET_JACK_THR_88PCT,
+	DA7218_HPLDET_JACK_THR_92PCT,
+	DA7218_HPLDET_JACK_THR_96PCT,
+};
+
+struct da7218_hpldet_pdata {
+	enum da7218_hpldet_jack_rate jack_rate;
+	enum da7218_hpldet_jack_debounce jack_debounce;
+	enum da7218_hpldet_jack_thr jack_thr;
+	bool comp_inv;
+	bool hyst;
+	bool discharge;
+};
+
+struct da7218_pdata {
+	/* Mic */
+	enum da7218_micbias_voltage micbias1_lvl;
+	enum da7218_micbias_voltage micbias2_lvl;
+	enum da7218_mic_amp_in_sel mic1_amp_in_sel;
+	enum da7218_mic_amp_in_sel mic2_amp_in_sel;
+
+	/* DMIC */
+	enum da7218_dmic_data_sel dmic1_data_sel;
+	enum da7218_dmic_data_sel dmic2_data_sel;
+	enum da7218_dmic_samplephase dmic1_samplephase;
+	enum da7218_dmic_samplephase dmic2_samplephase;
+	enum da7218_dmic_clk_rate dmic1_clk_rate;
+	enum da7218_dmic_clk_rate dmic2_clk_rate;
+
+	/* HP Diff Supply - DA7217 only */
+	bool hp_diff_single_supply;
+
+	/* HP Detect - DA7218 only */
+	struct da7218_hpldet_pdata *hpldet_pdata;
+};
+
+#endif /* _DA7218_PDATA_H */
diff --git a/include/sound/da7219.h b/include/sound/da7219.h
index 3f39e13..02876ac 100644
--- a/include/sound/da7219.h
+++ b/include/sound/da7219.h
@@ -14,17 +14,10 @@
 #ifndef __DA7219_PDATA_H
 #define __DA7219_PDATA_H
 
-/* LDO */
-enum da7219_ldo_lvl_sel {
-	DA7219_LDO_LVL_SEL_1_05V = 0,
-	DA7219_LDO_LVL_SEL_1_10V,
-	DA7219_LDO_LVL_SEL_1_20V,
-	DA7219_LDO_LVL_SEL_1_40V,
-};
-
 /* Mic Bias */
 enum da7219_micbias_voltage {
-	DA7219_MICBIAS_1_8V = 1,
+	DA7219_MICBIAS_1_6V = 0,
+	DA7219_MICBIAS_1_8V,
 	DA7219_MICBIAS_2_0V,
 	DA7219_MICBIAS_2_2V,
 	DA7219_MICBIAS_2_4V,
@@ -41,9 +34,6 @@
 struct da7219_aad_pdata;
 
 struct da7219_pdata {
-	/* Internal LDO */
-	enum da7219_ldo_lvl_sel ldo_lvl_sel;
-
 	/* Mic */
 	enum da7219_micbias_voltage micbias_lvl;
 	enum da7219_mic_amp_in_sel mic_amp_in_sel;
diff --git a/include/sound/designware_i2s.h b/include/sound/designware_i2s.h
index 8966ba7..5681855 100644
--- a/include/sound/designware_i2s.h
+++ b/include/sound/designware_i2s.h
@@ -45,6 +45,12 @@
 	u32 snd_fmts;
 	u32 snd_rates;
 
+	#define DW_I2S_QUIRK_COMP_REG_OFFSET	(1 << 0)
+	#define DW_I2S_QUIRK_COMP_PARAM1	(1 << 1)
+	unsigned int quirks;
+	unsigned int i2s_reg_comp1;
+	unsigned int i2s_reg_comp2;
+
 	void *play_dma_data;
 	void *capture_dma_data;
 	bool (*filter)(struct dma_chan *chan, void *slave);
diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h
index 930b41e..fa341fc 100644
--- a/include/sound/hda_i915.h
+++ b/include/sound/hda_i915.h
@@ -10,6 +10,9 @@
 int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);
 int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
 int snd_hdac_get_display_clk(struct hdac_bus *bus);
+int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, int rate);
+int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid,
+			   bool *audio_enabled, char *buffer, int max_bytes);
 int snd_hdac_i915_init(struct hdac_bus *bus);
 int snd_hdac_i915_exit(struct hdac_bus *bus);
 int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *);
@@ -26,6 +29,17 @@
 {
 	return 0;
 }
+static inline int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid,
+					   int rate)
+{
+	return 0;
+}
+static inline int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid,
+					 bool *audio_enabled, char *buffer,
+					 int max_bytes)
+{
+	return -ENODEV;
+}
 static inline int snd_hdac_i915_init(struct hdac_bus *bus)
 {
 	return -ENODEV;
diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h
index 94dc6a9..ff1aecf 100644
--- a/include/sound/hda_register.h
+++ b/include/sound/hda_register.h
@@ -233,6 +233,15 @@
 #define AZX_MLCTL_SPA			(1<<16)
 #define AZX_MLCTL_CPA			23
 
+
+/* registers for DMA Resume Capability Structure */
+#define AZX_DRSM_CAP_ID			0x5
+#define AZX_REG_DRSM_CTL		0x4
+/* Base used to calculate the iterating register offset */
+#define AZX_DRSM_BASE			0x08
+/* Interval used to calculate the iterating register offset */
+#define AZX_DRSM_INTERVAL		0x08
+
 /*
  * helpers to read the stream position
  */
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h
index a4cadd9..07fa592 100644
--- a/include/sound/hdaudio_ext.h
+++ b/include/sound/hdaudio_ext.h
@@ -12,6 +12,7 @@
  * @spbcap: SPIB capabilities pointer
  * @mlcap: MultiLink capabilities pointer
  * @gtscap: gts capabilities pointer
+ * @drsmcap: dma resume capabilities pointer
  * @hlink_list: link list of HDA links
  */
 struct hdac_ext_bus {
@@ -23,6 +24,7 @@
 	void __iomem *spbcap;
 	void __iomem *mlcap;
 	void __iomem *gtscap;
+	void __iomem *drsmcap;
 
 	struct list_head hlink_list;
 };
@@ -72,6 +74,9 @@
  * @pplc_addr: processing pipe link stream pointer
  * @spib_addr: software position in buffers stream pointer
  * @fifo_addr: software position Max fifos stream pointer
+ * @dpibr_addr: DMA position in buffer resume pointer
+ * @dpib: DMA position in buffer
+ * @lpib: Linear position in buffer
  * @decoupled: stream host and link is decoupled
  * @link_locked: link is locked
  * @link_prepared: link is prepared
@@ -86,6 +91,10 @@
 	void __iomem *spib_addr;
 	void __iomem *fifo_addr;
 
+	void __iomem *dpibr_addr;
+
+	u32 dpib;
+	u32 lpib;
 	bool decoupled:1;
 	bool link_locked:1;
 	bool link_prepared;
@@ -116,6 +125,11 @@
 				 struct hdac_ext_stream *stream, u32 value);
 int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus,
 				 struct hdac_ext_stream *stream);
+void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
+				bool enable, int index);
+int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
+				struct hdac_ext_stream *stream, u32 value);
+int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value);
 
 void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hstream);
 void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hstream);
@@ -133,6 +147,7 @@
 
 int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link);
 int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link);
+int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus);
 int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus);
 void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
 				 int stream);
@@ -186,9 +201,15 @@
 	/* codec ops */
 	struct hdac_ext_codec_ops ops;
 
+	struct snd_card *card;
+	void *scodec;
 	void *private_data;
 };
 
+struct hdac_ext_dma_params {
+	u32 format;
+	u8 stream_tag;
+};
 #define to_ehdac_device(dev) (container_of((dev), \
 				 struct hdac_ext_device, hdac))
 /*
diff --git a/include/sound/i2c.h b/include/sound/i2c.h
index d125ff8..835254d 100644
--- a/include/sound/i2c.h
+++ b/include/sound/i2c.h
@@ -66,7 +66,7 @@
 		struct snd_i2c_bit_ops *bit;
 		void *ops;
 	} hw_ops;		/* lowlevel operations */
-	struct snd_i2c_ops *ops;	/* midlevel operations */
+	const struct snd_i2c_ops *ops;	/* midlevel operations */
 
 	unsigned long private_value;
 	void *private_data;
diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h
index f6cbef7..fdabbb4 100644
--- a/include/sound/rawmidi.h
+++ b/include/sound/rawmidi.h
@@ -130,7 +130,7 @@
 	int ossreg;
 #endif
 
-	struct snd_rawmidi_global_ops *ops;
+	const struct snd_rawmidi_global_ops *ops;
 
 	struct snd_rawmidi_str streams[2];
 
diff --git a/include/sound/rt5659.h b/include/sound/rt5659.h
new file mode 100644
index 0000000..656c4d5
--- /dev/null
+++ b/include/sound/rt5659.h
@@ -0,0 +1,49 @@
+/*
+ * linux/sound/rt5659.h -- Platform data for RT5659
+ *
+ * Copyright 2013 Realtek Microelectronics
+ *
+ * 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_RT5659_H
+#define __LINUX_SND_RT5659_H
+
+enum rt5659_dmic1_data_pin {
+	RT5659_DMIC1_NULL,
+	RT5659_DMIC1_DATA_IN2N,
+	RT5659_DMIC1_DATA_GPIO5,
+	RT5659_DMIC1_DATA_GPIO9,
+	RT5659_DMIC1_DATA_GPIO11,
+};
+
+enum rt5659_dmic2_data_pin {
+	RT5659_DMIC2_NULL,
+	RT5659_DMIC2_DATA_IN2P,
+	RT5659_DMIC2_DATA_GPIO6,
+	RT5659_DMIC2_DATA_GPIO10,
+	RT5659_DMIC2_DATA_GPIO12,
+};
+
+enum rt5659_jd_src {
+	RT5659_JD_NULL,
+	RT5659_JD3,
+};
+
+struct rt5659_platform_data {
+	bool in1_diff;
+	bool in3_diff;
+	bool in4_diff;
+
+	int ldo1_en; /* GPIO for LDO1_EN */
+	int reset; /* GPIO for RESET */
+
+	enum rt5659_dmic1_data_pin dmic1_data_pin;
+	enum rt5659_dmic2_data_pin dmic2_data_pin;
+	enum rt5659_jd_src jd_src;
+};
+
+#endif
+
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 212eaaf..964b7de 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -222,6 +222,7 @@
 	const char *name;
 	unsigned int id;
 	unsigned int base;
+	struct snd_soc_dobj dobj;
 
 	/* DAI driver callbacks */
 	int (*probe)(struct snd_soc_dai *dai);
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 95a937e..9706946 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -49,6 +49,9 @@
 #define SND_SOC_DAPM_SIGGEN(wname) \
 {	.id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
+#define SND_SOC_DAPM_SINK(wname) \
+{	.id = snd_soc_dapm_sink, .name = wname, .kcontrol_news = NULL, \
+	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_INPUT(wname) \
 {	.id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
@@ -485,6 +488,7 @@
 	snd_soc_dapm_aif_in,		/* audio interface input */
 	snd_soc_dapm_aif_out,		/* audio interface output */
 	snd_soc_dapm_siggen,		/* signal generator */
+	snd_soc_dapm_sink,
 	snd_soc_dapm_dai_in,		/* link to DAI structure */
 	snd_soc_dapm_dai_out,
 	snd_soc_dapm_dai_link,		/* link between two DAI structures */
diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h
index 086cd7f..5b68e3f 100644
--- a/include/sound/soc-topology.h
+++ b/include/sound/soc-topology.h
@@ -92,8 +92,10 @@
 /* Bytes ext operations, for TLV byte controls */
 struct snd_soc_tplg_bytes_ext_ops {
 	u32 id;
-	int (*get)(unsigned int __user *bytes, unsigned int size);
-	int (*put)(const unsigned int __user *bytes, unsigned int size);
+	int (*get)(struct snd_kcontrol *kcontrol, unsigned int __user *bytes,
+							unsigned int size);
+	int (*put)(struct snd_kcontrol *kcontrol,
+			const unsigned int __user *bytes, unsigned int size);
 };
 
 /*
diff --git a/include/sound/soc.h b/include/sound/soc.h
index fb955e6..7afb72c 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -110,6 +110,14 @@
 	.put = snd_soc_put_volsw, \
 	.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
 					  max, invert, 0) }
+#define SOC_DOUBLE_STS(xname, reg, shift_left, shift_right, max, invert) \
+{									\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),		\
+	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,		\
+	.access = SNDRV_CTL_ELEM_ACCESS_READ |				\
+		SNDRV_CTL_ELEM_ACCESS_VOLATILE,				\
+	.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right,	\
+					  max, invert, 0) }
 #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 	.info = snd_soc_info_volsw, \
@@ -293,6 +301,9 @@
 		{.base = xbase, .num_regs = xregs,	      \
 		 .mask = xmask }) }
 
+/*
+ * SND_SOC_BYTES_EXT is deprecated, please USE SND_SOC_BYTES_TLV instead
+ */
 #define SND_SOC_BYTES_EXT(xname, xcount, xhandler_get, xhandler_put) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.info = snd_soc_bytes_info_ext, \
@@ -787,6 +798,7 @@
 	unsigned int registered_as_component:1;
 
 	struct list_head list;
+	struct list_head list_aux; /* for auxiliary component of the card */
 
 	struct snd_soc_dai_driver *dai_drv;
 	int num_dai;
@@ -830,6 +842,9 @@
 	int (*probe)(struct snd_soc_component *);
 	void (*remove)(struct snd_soc_component *);
 
+	/* machine specific init */
+	int (*init)(struct snd_soc_component *component);
+
 #ifdef CONFIG_DEBUG_FS
 	void (*init_debugfs)(struct snd_soc_component *component);
 	const char *debugfs_prefix;
@@ -1037,6 +1052,9 @@
 
 	/* pmdown_time is ignored at stop */
 	unsigned int ignore_pmdown_time:1;
+
+	struct list_head list; /* DAI link list of the soc card */
+	struct snd_soc_dobj dobj; /* For topology */
 };
 
 struct snd_soc_codec_conf {
@@ -1101,12 +1119,20 @@
 				   struct snd_soc_dapm_context *dapm,
 				   enum snd_soc_bias_level level);
 
+	int (*add_dai_link)(struct snd_soc_card *,
+			    struct snd_soc_dai_link *link);
+	void (*remove_dai_link)(struct snd_soc_card *,
+			    struct snd_soc_dai_link *link);
+
 	long pmdown_time;
 
 	/* CPU <--> Codec DAI links  */
-	struct snd_soc_dai_link *dai_link;
-	int num_links;
-	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai_link *dai_link;  /* predefined links only */
+	int num_links;  /* predefined links only */
+	struct list_head dai_link_list; /* all links */
+	int num_dai_links;
+
+	struct list_head rtd_list;
 	int num_rtd;
 
 	/* optional codec specific configuration */
@@ -1119,8 +1145,7 @@
 	 */
 	struct snd_soc_aux_dev *aux_dev;
 	int num_aux_devs;
-	struct snd_soc_pcm_runtime *rtd_aux;
-	int num_aux_rtd;
+	struct list_head aux_comp_list;
 
 	const struct snd_kcontrol_new *controls;
 	int num_controls;
@@ -1201,6 +1226,9 @@
 	struct dentry *debugfs_dpcm_root;
 	struct dentry *debugfs_dpcm_state;
 #endif
+
+	unsigned int num; /* 0-based and monotonic increasing */
+	struct list_head list; /* rtd list of the soc card */
 };
 
 /* mixer control */
@@ -1225,8 +1253,10 @@
 	struct snd_soc_dobj dobj;
 
 	/* used for TLV byte control */
-	int (*get)(unsigned int __user *bytes, unsigned int size);
-	int (*put)(const unsigned int __user *bytes, unsigned int size);
+	int (*get)(struct snd_kcontrol *kcontrol, unsigned int __user *bytes,
+			unsigned int size);
+	int (*put)(struct snd_kcontrol *kcontrol, const unsigned int __user *bytes,
+			unsigned int size);
 };
 
 /* multi register control */
@@ -1523,6 +1553,7 @@
 	INIT_LIST_HEAD(&card->widgets);
 	INIT_LIST_HEAD(&card->paths);
 	INIT_LIST_HEAD(&card->dapm_list);
+	INIT_LIST_HEAD(&card->aux_comp_list);
 }
 
 static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
@@ -1644,6 +1675,14 @@
 				   struct device_node *of_node,
 				   struct snd_soc_dai_link *dai_link);
 
+int snd_soc_add_dai_link(struct snd_soc_card *card,
+				struct snd_soc_dai_link *dai_link);
+void snd_soc_remove_dai_link(struct snd_soc_card *card,
+			     struct snd_soc_dai_link *dai_link);
+
+int snd_soc_register_dai(struct snd_soc_component *component,
+	struct snd_soc_dai_driver *dai_drv);
+
 #include <sound/soc-dai.h>
 
 #ifdef CONFIG_DEBUG_FS
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 484a9fb..67ef73a 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -1079,6 +1079,12 @@
 };
 
 struct drm_i915_reg_read {
+	/*
+	 * Register offset.
+	 * For 64bit wide registers where the upper 32bits don't immediately
+	 * follow the lower 32bits, the offset of the lower 32bits must
+	 * be specified
+	 */
 	__u64 offset;
 	__u64 val; /* Return value */
 };
@@ -1125,8 +1131,9 @@
 	__u32 ctx_id;
 	__u32 size;
 	__u64 param;
-#define I915_CONTEXT_PARAM_BAN_PERIOD 0x1
-#define I915_CONTEXT_PARAM_NO_ZEROMAP 0x2
+#define I915_CONTEXT_PARAM_BAN_PERIOD	0x1
+#define I915_CONTEXT_PARAM_NO_ZEROMAP	0x2
+#define I915_CONTEXT_PARAM_GTT_SIZE	0x3
 	__u64 value;
 };
 
diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h
index 26539a7..c4cc1e4 100644
--- a/include/uapi/sound/asoc.h
+++ b/include/uapi/sound/asoc.h
@@ -243,7 +243,7 @@
 	__le32 control_elems;	/* number of control elements */
 	__le32 widget_elems;	/* number of widget elements */
 	__le32 graph_elems;	/* number of graph elements */
-	__le32 dai_elems;	/* number of DAI elements */
+	__le32 pcm_elems;	/* number of PCM elements */
 	__le32 dai_link_elems;	/* number of DAI link elements */
 	struct snd_soc_tplg_private priv;
 } __attribute__((packed));
diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h
index d9bd9ca..9625484 100644
--- a/include/uapi/sound/compress_params.h
+++ b/include/uapi/sound/compress_params.h
@@ -73,7 +73,8 @@
 #define SND_AUDIOCODEC_IEC61937              ((__u32) 0x0000000B)
 #define SND_AUDIOCODEC_G723_1                ((__u32) 0x0000000C)
 #define SND_AUDIOCODEC_G729                  ((__u32) 0x0000000D)
-#define SND_AUDIOCODEC_MAX                   SND_AUDIOCODEC_G729
+#define SND_AUDIOCODEC_BESPOKE               ((__u32) 0x0000000E)
+#define SND_AUDIOCODEC_MAX                   SND_AUDIOCODEC_BESPOKE
 
 /*
  * Profile and modes are listed with bit masks. This allows for a
@@ -312,7 +313,7 @@
 
 struct snd_enc_generic {
 	__u32 bw;	/* encoder bandwidth */
-	__s32 reserved[15];
+	__s32 reserved[15];	/* Can be used for SND_AUDIOCODEC_BESPOKE */
 } __attribute__((packed, aligned(4)));
 
 union snd_codec_options {
diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c
index e5d059e..8a09b32 100644
--- a/init/do_mounts_rd.c
+++ b/init/do_mounts_rd.c
@@ -216,13 +216,6 @@
 	/*
 	 * NOTE NOTE: nblocks is not actually blocks but
 	 * the number of kibibytes of data to load into a ramdisk.
-	 * So any ramdisk block size that is a multiple of 1KiB should
-	 * work when the appropriate ramdisk_blocksize is specified
-	 * on the command line.
-	 *
-	 * The default ramdisk_blocksize is 1KiB and it is generally
-	 * silly to use anything else, so make sure to use 1KiB
-	 * blocksize while generating ext2fs ramdisk-images.
 	 */
 	if (sys_ioctl(out_fd, BLKGETSIZE, (unsigned long)&rd_blocks) < 0)
 		rd_blocks = 0;
diff --git a/kernel/async.c b/kernel/async.c
index 4c3773c..d2edd6e 100644
--- a/kernel/async.c
+++ b/kernel/async.c
@@ -326,3 +326,4 @@
 
 	return worker && worker->current_func == async_run_entry_fn;
 }
+EXPORT_SYMBOL_GPL(current_is_async);
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 638a38e..c37255b 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -1816,6 +1816,8 @@
 	$members =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i;
 	$members =~ s/__aligned\s*\([^;]*\)//gos;
 	$members =~ s/\s*CRYPTO_MINALIGN_ATTR//gos;
+	# replace DECLARE_BITMAP
+	$members =~ s/DECLARE_BITMAP\s*\(([^,)]+), ([^,)]+)\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos;
 
 	create_parameterlist($members, ';', $file);
 	check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested);
@@ -1844,7 +1846,8 @@
     my $file = shift;
 
     $x =~ s@/\*.*?\*/@@gos;	# strip comments.
-    $x =~ s/^#\s*define\s+.*$//; # strip #define macros inside enums
+    # strip #define macros inside enums
+    $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos;
 
     if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
 	$declaration_name = $1;
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index b123c42..18b8dc4 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -38,8 +38,10 @@
 #include <linux/uio.h>
 #include <linux/uaccess.h>
 #include <linux/module.h>
+#include <linux/compat.h>
 #include <sound/core.h>
 #include <sound/initval.h>
+#include <sound/info.h>
 #include <sound/compress_params.h>
 #include <sound/compress_offload.h>
 #include <sound/compress_driver.h>
@@ -847,6 +849,15 @@
 	return retval;
 }
 
+/* support of 32bit userspace on 64bit platforms */
+#ifdef CONFIG_COMPAT
+static long snd_compr_ioctl_compat(struct file *file, unsigned int cmd,
+						unsigned long arg)
+{
+	return snd_compr_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
 static const struct file_operations snd_compr_file_ops = {
 		.owner =	THIS_MODULE,
 		.open =		snd_compr_open,
@@ -854,6 +865,9 @@
 		.write =	snd_compr_write,
 		.read =		snd_compr_read,
 		.unlocked_ioctl = snd_compr_ioctl,
+#ifdef CONFIG_COMPAT
+		.compat_ioctl = snd_compr_ioctl_compat,
+#endif
 		.mmap =		snd_compr_mmap,
 		.poll =		snd_compr_poll,
 };
@@ -891,11 +905,85 @@
 	return 0;
 }
 
+#ifdef CONFIG_SND_VERBOSE_PROCFS
+static void snd_compress_proc_info_read(struct snd_info_entry *entry,
+					struct snd_info_buffer *buffer)
+{
+	struct snd_compr *compr = (struct snd_compr *)entry->private_data;
+
+	snd_iprintf(buffer, "card: %d\n", compr->card->number);
+	snd_iprintf(buffer, "device: %d\n", compr->device);
+	snd_iprintf(buffer, "stream: %s\n",
+			compr->direction == SND_COMPRESS_PLAYBACK
+				? "PLAYBACK" : "CAPTURE");
+	snd_iprintf(buffer, "id: %s\n", compr->id);
+}
+
+static int snd_compress_proc_init(struct snd_compr *compr)
+{
+	struct snd_info_entry *entry;
+	char name[16];
+
+	sprintf(name, "compr%i", compr->device);
+	entry = snd_info_create_card_entry(compr->card, name,
+					   compr->card->proc_root);
+	if (!entry)
+		return -ENOMEM;
+	entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+	if (snd_info_register(entry) < 0) {
+		snd_info_free_entry(entry);
+		return -ENOMEM;
+	}
+	compr->proc_root = entry;
+
+	entry = snd_info_create_card_entry(compr->card, "info",
+					   compr->proc_root);
+	if (entry) {
+		snd_info_set_text_ops(entry, compr,
+				      snd_compress_proc_info_read);
+		if (snd_info_register(entry) < 0) {
+			snd_info_free_entry(entry);
+			entry = NULL;
+		}
+	}
+	compr->proc_info_entry = entry;
+
+	return 0;
+}
+
+static void snd_compress_proc_done(struct snd_compr *compr)
+{
+	snd_info_free_entry(compr->proc_info_entry);
+	compr->proc_info_entry = NULL;
+	snd_info_free_entry(compr->proc_root);
+	compr->proc_root = NULL;
+}
+
+static inline void snd_compress_set_id(struct snd_compr *compr, const char *id)
+{
+	strlcpy(compr->id, id, sizeof(compr->id));
+}
+#else
+static inline int snd_compress_proc_init(struct snd_compr *compr)
+{
+	return 0;
+}
+
+static inline void snd_compress_proc_done(struct snd_compr *compr)
+{
+}
+
+static inline void snd_compress_set_id(struct snd_compr *compr, const char *id)
+{
+}
+#endif
+
 static int snd_compress_dev_free(struct snd_device *device)
 {
 	struct snd_compr *compr;
 
 	compr = device->device_data;
+	snd_compress_proc_done(compr);
 	put_device(&compr->dev);
 	return 0;
 }
@@ -908,22 +996,29 @@
  * @compr: compress device pointer
  */
 int snd_compress_new(struct snd_card *card, int device,
-			int dirn, struct snd_compr *compr)
+			int dirn, const char *id, struct snd_compr *compr)
 {
 	static struct snd_device_ops ops = {
 		.dev_free = snd_compress_dev_free,
 		.dev_register = snd_compress_dev_register,
 		.dev_disconnect = snd_compress_dev_disconnect,
 	};
+	int ret;
 
 	compr->card = card;
 	compr->device = device;
 	compr->direction = dirn;
 
+	snd_compress_set_id(compr, id);
+
 	snd_device_initialize(&compr->dev, card);
 	dev_set_name(&compr->dev, "comprC%iD%i", card->number, device);
 
-	return snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops);
+	ret = snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops);
+	if (ret == 0)
+		snd_compress_proc_init(compr);
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_compress_new);
 
diff --git a/sound/core/init.c b/sound/core/init.c
index 20f37fb..6bda843 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -268,6 +268,9 @@
 	if (err < 0)
 		goto __error;
 
+	snprintf(card->irq_descr, sizeof(card->irq_descr), "%s:%s",
+		 dev_driver_string(card->dev), dev_name(&card->card_dev));
+
 	/* the control interface cannot be accessed from the user space until */
 	/* snd_cards_bitmask and snd_cards are set with snd_card_register */
 	err = snd_ctl_create(card);
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 7a8c79d..2ff9c12 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -24,6 +24,7 @@
 #include <linux/time.h>
 #include <linux/string.h>
 #include <linux/module.h>
+#include <linux/compat.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/control.h>
@@ -397,7 +398,12 @@
 
 #ifdef CONFIG_COMPAT
 /* all compatible */
-#define snd_mixer_oss_ioctl_compat	snd_mixer_oss_ioctl
+static long snd_mixer_oss_ioctl_compat(struct file *file, unsigned int cmd,
+				       unsigned long arg)
+{
+	return snd_mixer_oss_ioctl1(file->private_data, cmd,
+				    (unsigned long)compat_ptr(arg));
+}
 #else
 #define snd_mixer_oss_ioctl_compat	NULL
 #endif
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 58550cc..0e73d03 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -33,6 +33,7 @@
 #include <linux/module.h>
 #include <linux/math64.h>
 #include <linux/string.h>
+#include <linux/compat.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/pcm.h>
@@ -850,7 +851,7 @@
 
 	if (mutex_lock_interruptible(&runtime->oss.params_lock))
 		return -EINTR;
-	sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL);
+	sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL);
 	params = kmalloc(sizeof(*params), GFP_KERNEL);
 	sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
 	if (!sw_params || !params || !sparams) {
@@ -988,7 +989,6 @@
 		goto failure;
 	}
 
-	memset(sw_params, 0, sizeof(*sw_params));
 	if (runtime->oss.trigger) {
 		sw_params->start_threshold = 1;
 	} else {
@@ -2648,7 +2648,11 @@
 
 #ifdef CONFIG_COMPAT
 /* all compatible */
-#define snd_pcm_oss_ioctl_compat	snd_pcm_oss_ioctl
+static long snd_pcm_oss_ioctl_compat(struct file *file, unsigned int cmd,
+				     unsigned long arg)
+{
+	return snd_pcm_oss_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+}
 #else
 #define snd_pcm_oss_ioctl_compat	NULL
 #endif
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index a8b27cd..fadd3eb 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -875,7 +875,7 @@
  *  Note: the stream state might be changed also on failure
  *  Note2: call with calling stream lock + link lock
  */
-static int snd_pcm_action_group(struct action_ops *ops,
+static int snd_pcm_action_group(const struct action_ops *ops,
 				struct snd_pcm_substream *substream,
 				int state, int do_lock)
 {
@@ -932,7 +932,7 @@
 /*
  *  Note: call with stream lock
  */
-static int snd_pcm_action_single(struct action_ops *ops,
+static int snd_pcm_action_single(const struct action_ops *ops,
 				 struct snd_pcm_substream *substream,
 				 int state)
 {
@@ -952,7 +952,7 @@
 /*
  *  Note: call with stream lock
  */
-static int snd_pcm_action(struct action_ops *ops,
+static int snd_pcm_action(const struct action_ops *ops,
 			  struct snd_pcm_substream *substream,
 			  int state)
 {
@@ -984,7 +984,7 @@
 /*
  *  Note: don't use any locks before
  */
-static int snd_pcm_action_lock_irq(struct action_ops *ops,
+static int snd_pcm_action_lock_irq(const struct action_ops *ops,
 				   struct snd_pcm_substream *substream,
 				   int state)
 {
@@ -998,7 +998,7 @@
 
 /*
  */
-static int snd_pcm_action_nonatomic(struct action_ops *ops,
+static int snd_pcm_action_nonatomic(const struct action_ops *ops,
 				    struct snd_pcm_substream *substream,
 				    int state)
 {
@@ -1056,7 +1056,7 @@
 	snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTART);
 }
 
-static struct action_ops snd_pcm_action_start = {
+static const struct action_ops snd_pcm_action_start = {
 	.pre_action = snd_pcm_pre_start,
 	.do_action = snd_pcm_do_start,
 	.undo_action = snd_pcm_undo_start,
@@ -1107,7 +1107,7 @@
 	wake_up(&runtime->tsleep);
 }
 
-static struct action_ops snd_pcm_action_stop = {
+static const struct action_ops snd_pcm_action_stop = {
 	.pre_action = snd_pcm_pre_stop,
 	.do_action = snd_pcm_do_stop,
 	.post_action = snd_pcm_post_stop
@@ -1224,7 +1224,7 @@
 	}
 }
 
-static struct action_ops snd_pcm_action_pause = {
+static const struct action_ops snd_pcm_action_pause = {
 	.pre_action = snd_pcm_pre_pause,
 	.do_action = snd_pcm_do_pause,
 	.undo_action = snd_pcm_undo_pause,
@@ -1273,7 +1273,7 @@
 	wake_up(&runtime->tsleep);
 }
 
-static struct action_ops snd_pcm_action_suspend = {
+static const struct action_ops snd_pcm_action_suspend = {
 	.pre_action = snd_pcm_pre_suspend,
 	.do_action = snd_pcm_do_suspend,
 	.post_action = snd_pcm_post_suspend
@@ -1375,7 +1375,7 @@
 	snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MRESUME);
 }
 
-static struct action_ops snd_pcm_action_resume = {
+static const struct action_ops snd_pcm_action_resume = {
 	.pre_action = snd_pcm_pre_resume,
 	.do_action = snd_pcm_do_resume,
 	.undo_action = snd_pcm_undo_resume,
@@ -1478,7 +1478,7 @@
 		snd_pcm_playback_silence(substream, ULONG_MAX);
 }
 
-static struct action_ops snd_pcm_action_reset = {
+static const struct action_ops snd_pcm_action_reset = {
 	.pre_action = snd_pcm_pre_reset,
 	.do_action = snd_pcm_do_reset,
 	.post_action = snd_pcm_post_reset
@@ -1522,7 +1522,7 @@
 	snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED);
 }
 
-static struct action_ops snd_pcm_action_prepare = {
+static const struct action_ops snd_pcm_action_prepare = {
 	.pre_action = snd_pcm_pre_prepare,
 	.do_action = snd_pcm_do_prepare,
 	.post_action = snd_pcm_post_prepare
@@ -1618,7 +1618,7 @@
 {
 }
 
-static struct action_ops snd_pcm_action_drain_init = {
+static const struct action_ops snd_pcm_action_drain_init = {
 	.pre_action = snd_pcm_pre_drain_init,
 	.do_action = snd_pcm_do_drain_init,
 	.post_action = snd_pcm_post_drain_init
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index 7354b8b..8db156b 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/compat.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/initval.h>
@@ -189,7 +190,11 @@
 }
 
 #ifdef CONFIG_COMPAT
-#define odev_ioctl_compat	odev_ioctl
+static long odev_ioctl_compat(struct file *file, unsigned int cmd,
+			      unsigned long arg)
+{
+	return odev_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+}
 #else
 #define odev_ioctl_compat	NULL
 #endif
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index b64f20d..13cfa81 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1962,7 +1962,7 @@
 		 * No restrictions so for a user client we can clear
 		 * the whole fifo
 		 */
-		if (client->type == USER_CLIENT)
+		if (client->type == USER_CLIENT && client->data.user.fifo)
 			snd_seq_fifo_clear(client->data.user.fifo);
 	}
 
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index 7dfd0f4..0bec02e 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -142,8 +142,10 @@
 static void queue_delete(struct snd_seq_queue *q)
 {
 	/* stop and release the timer */
+	mutex_lock(&q->timer_mutex);
 	snd_seq_timer_stop(q->timer);
 	snd_seq_timer_close(q);
+	mutex_unlock(&q->timer_mutex);
 	/* wait until access free */
 	snd_use_lock_sync(&q->use_lock);
 	/* release resources... */
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index 56e0f4cd..3da2d48 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -468,7 +468,7 @@
 /*
  *
  */
-static struct snd_rawmidi_global_ops snd_virmidi_global_ops = {
+static const struct snd_rawmidi_global_ops snd_virmidi_global_ops = {
 	.dev_register = snd_virmidi_dev_register,
 	.dev_unregister = snd_virmidi_dev_unregister,
 };
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 31f40f0..cb25ade 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -73,7 +73,7 @@
 	struct timespec tstamp;		/* trigger tstamp */
 	wait_queue_head_t qchange_sleep;
 	struct fasync_struct *fasync;
-	struct mutex tread_sem;
+	struct mutex ioctl_lock;
 };
 
 /* list of timers */
@@ -215,11 +215,13 @@
 		    slave->slave_id == master->slave_id) {
 			list_move_tail(&slave->open_list, &master->slave_list_head);
 			spin_lock_irq(&slave_active_lock);
+			spin_lock(&master->timer->lock);
 			slave->master = master;
 			slave->timer = master->timer;
 			if (slave->flags & SNDRV_TIMER_IFLG_RUNNING)
 				list_add_tail(&slave->active_list,
 					      &master->slave_active_head);
+			spin_unlock(&master->timer->lock);
 			spin_unlock_irq(&slave_active_lock);
 		}
 	}
@@ -299,8 +301,7 @@
 	return 0;
 }
 
-static int _snd_timer_stop(struct snd_timer_instance *timeri,
-			   int keep_flag, int event);
+static int _snd_timer_stop(struct snd_timer_instance *timeri, int event);
 
 /*
  * close a timer instance
@@ -342,19 +343,22 @@
 		spin_unlock_irq(&timer->lock);
 		mutex_lock(&register_mutex);
 		list_del(&timeri->open_list);
-		if (timer && list_empty(&timer->open_list_head) &&
+		if (list_empty(&timer->open_list_head) &&
 		    timer->hw.close)
 			timer->hw.close(timer);
 		/* remove slave links */
+		spin_lock_irq(&slave_active_lock);
+		spin_lock(&timer->lock);
 		list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
 					 open_list) {
-			spin_lock_irq(&slave_active_lock);
-			_snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION);
 			list_move_tail(&slave->open_list, &snd_timer_slave_list);
 			slave->master = NULL;
 			slave->timer = NULL;
-			spin_unlock_irq(&slave_active_lock);
+			list_del_init(&slave->ack_list);
+			list_del_init(&slave->active_list);
 		}
+		spin_unlock(&timer->lock);
+		spin_unlock_irq(&slave_active_lock);
 		mutex_unlock(&register_mutex);
 	}
  out:
@@ -441,9 +445,12 @@
 
 	spin_lock_irqsave(&slave_active_lock, flags);
 	timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
-	if (timeri->master)
+	if (timeri->master && timeri->timer) {
+		spin_lock(&timeri->timer->lock);
 		list_add_tail(&timeri->active_list,
 			      &timeri->master->slave_active_head);
+		spin_unlock(&timeri->timer->lock);
+	}
 	spin_unlock_irqrestore(&slave_active_lock, flags);
 	return 1; /* delayed start */
 }
@@ -476,8 +483,7 @@
 	return result;
 }
 
-static int _snd_timer_stop(struct snd_timer_instance * timeri,
-			   int keep_flag, int event)
+static int _snd_timer_stop(struct snd_timer_instance *timeri, int event)
 {
 	struct snd_timer *timer;
 	unsigned long flags;
@@ -486,11 +492,11 @@
 		return -ENXIO;
 
 	if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
-		if (!keep_flag) {
-			spin_lock_irqsave(&slave_active_lock, flags);
-			timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
-			spin_unlock_irqrestore(&slave_active_lock, flags);
-		}
+		spin_lock_irqsave(&slave_active_lock, flags);
+		timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
+		list_del_init(&timeri->ack_list);
+		list_del_init(&timeri->active_list);
+		spin_unlock_irqrestore(&slave_active_lock, flags);
 		goto __end;
 	}
 	timer = timeri->timer;
@@ -511,9 +517,7 @@
 			}
 		}
 	}
-	if (!keep_flag)
-		timeri->flags &=
-			~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START);
+	timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START);
 	spin_unlock_irqrestore(&timer->lock, flags);
       __end:
 	if (event != SNDRV_TIMER_EVENT_RESOLUTION)
@@ -532,7 +536,7 @@
 	unsigned long flags;
 	int err;
 
-	err = _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_STOP);
+	err = _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_STOP);
 	if (err < 0)
 		return err;
 	timer = timeri->timer;
@@ -576,7 +580,7 @@
  */
 int snd_timer_pause(struct snd_timer_instance * timeri)
 {
-	return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE);
+	return _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_PAUSE);
 }
 
 /*
@@ -694,7 +698,7 @@
 		} else {
 			ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
 			if (--timer->running)
-				list_del(&ti->active_list);
+				list_del_init(&ti->active_list);
 		}
 		if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
 		    (ti->flags & SNDRV_TIMER_IFLG_FAST))
@@ -1253,7 +1257,7 @@
 		return -ENOMEM;
 	spin_lock_init(&tu->qlock);
 	init_waitqueue_head(&tu->qchange_sleep);
-	mutex_init(&tu->tread_sem);
+	mutex_init(&tu->ioctl_lock);
 	tu->ticks = 1;
 	tu->queue_size = 128;
 	tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read),
@@ -1273,8 +1277,10 @@
 	if (file->private_data) {
 		tu = file->private_data;
 		file->private_data = NULL;
+		mutex_lock(&tu->ioctl_lock);
 		if (tu->timeri)
 			snd_timer_close(tu->timeri);
+		mutex_unlock(&tu->ioctl_lock);
 		kfree(tu->queue);
 		kfree(tu->tqueue);
 		kfree(tu);
@@ -1512,7 +1518,6 @@
 	int err = 0;
 
 	tu = file->private_data;
-	mutex_lock(&tu->tread_sem);
 	if (tu->timeri) {
 		snd_timer_close(tu->timeri);
 		tu->timeri = NULL;
@@ -1556,7 +1561,6 @@
 	}
 
       __err:
-      	mutex_unlock(&tu->tread_sem);
 	return err;
 }
 
@@ -1769,7 +1773,7 @@
 	SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23),
 };
 
-static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,
+static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd,
 				 unsigned long arg)
 {
 	struct snd_timer_user *tu;
@@ -1786,17 +1790,11 @@
 	{
 		int xarg;
 
-		mutex_lock(&tu->tread_sem);
-		if (tu->timeri)	{	/* too late */
-			mutex_unlock(&tu->tread_sem);
+		if (tu->timeri)	/* too late */
 			return -EBUSY;
-		}
-		if (get_user(xarg, p)) {
-			mutex_unlock(&tu->tread_sem);
+		if (get_user(xarg, p))
 			return -EFAULT;
-		}
 		tu->tread = xarg ? 1 : 0;
-		mutex_unlock(&tu->tread_sem);
 		return 0;
 	}
 	case SNDRV_TIMER_IOCTL_GINFO:
@@ -1829,6 +1827,18 @@
 	return -ENOTTY;
 }
 
+static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,
+				 unsigned long arg)
+{
+	struct snd_timer_user *tu = file->private_data;
+	long ret;
+
+	mutex_lock(&tu->ioctl_lock);
+	ret = __snd_timer_user_ioctl(file, cmd, arg);
+	mutex_unlock(&tu->ioctl_lock);
+	return ret;
+}
+
 static int snd_timer_user_fasync(int fd, struct file * file, int on)
 {
 	struct snd_timer_user *tu;
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 016e451..75b7485 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -351,7 +351,7 @@
 	kfree(substream->runtime->private_data);
 }
 
-static struct dummy_timer_ops dummy_systimer_ops = {
+static const struct dummy_timer_ops dummy_systimer_ops = {
 	.create =	dummy_systimer_create,
 	.free =		dummy_systimer_free,
 	.prepare =	dummy_systimer_prepare,
@@ -475,7 +475,7 @@
 	kfree(dpcm);
 }
 
-static struct dummy_timer_ops dummy_hrtimer_ops = {
+static const struct dummy_timer_ops dummy_hrtimer_ops = {
 	.create =	dummy_hrtimer_create,
 	.free =		dummy_hrtimer_free,
 	.prepare =	dummy_hrtimer_prepare,
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
index e92a6d9..2a779c2 100644
--- a/sound/firewire/Kconfig
+++ b/sound/firewire/Kconfig
@@ -39,6 +39,7 @@
 	   * Mackie(Loud) d.2 pro/d.4 pro
 	   * Mackie(Loud) U.420/U.420d
 	   * TASCAM FireOne
+	   * Stanton Controllers & Systems 1 Deck/Mixer
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-oxfw.
@@ -53,17 +54,6 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-isight.
 
-config SND_SCS1X
-	tristate "Stanton Control System 1 MIDI"
-	select SND_FIREWIRE_LIB
-	help
-	  Say Y here to include support for the MIDI ports of the Stanton
-	  SCS.1d/SCS.1m DJ controllers.  (SCS.1m audio is still handled
-	  by FFADO.)
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called snd-scs1x.
-
 config SND_FIREWORKS
 	tristate "Echo Fireworks board module support"
 	select SND_FIREWIRE_LIB
diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile
index f5fb625..003c090 100644
--- a/sound/firewire/Makefile
+++ b/sound/firewire/Makefile
@@ -1,13 +1,11 @@
 snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \
 			 fcp.o cmp.o amdtp-stream.o amdtp-am824.o
 snd-isight-objs := isight.o
-snd-scs1x-objs := scs1x.o
 
 obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o
 obj-$(CONFIG_SND_DICE) += dice/
 obj-$(CONFIG_SND_OXFW) += oxfw/
 obj-$(CONFIG_SND_ISIGHT) += snd-isight.o
-obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o
 obj-$(CONFIG_SND_FIREWORKS) += fireworks/
 obj-$(CONFIG_SND_BEBOB) += bebob/
 obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += digi00x/
diff --git a/sound/firewire/dice/dice-transaction.c b/sound/firewire/dice/dice-transaction.c
index aee7461..a4ff4e0 100644
--- a/sound/firewire/dice/dice-transaction.c
+++ b/sound/firewire/dice/dice-transaction.c
@@ -9,7 +9,7 @@
 
 #include "dice.h"
 
-#define NOTIFICATION_TIMEOUT_MS	100
+#define NOTIFICATION_TIMEOUT_MS	(2 * MSEC_PER_SEC)
 
 static u64 get_subaddr(struct snd_dice *dice, enum snd_dice_addr_type type,
 		       u64 offset)
@@ -65,16 +65,15 @@
 static int set_clock_info(struct snd_dice *dice,
 			  unsigned int rate, unsigned int source)
 {
-	unsigned int retries = 3;
 	unsigned int i;
 	__be32 info;
 	u32 mask;
 	u32 clock;
 	int err;
-retry:
+
 	err = get_clock_info(dice, &info);
 	if (err < 0)
-		goto end;
+		return err;
 
 	clock = be32_to_cpu(info);
 	if (source != UINT_MAX) {
@@ -87,10 +86,8 @@
 			if (snd_dice_rates[i] == rate)
 				break;
 		}
-		if (i == ARRAY_SIZE(snd_dice_rates)) {
-			err = -EINVAL;
-			goto end;
-		}
+		if (i == ARRAY_SIZE(snd_dice_rates))
+			return -EINVAL;
 
 		mask = CLOCK_RATE_MASK;
 		clock &= ~mask;
@@ -104,25 +101,13 @@
 	err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT,
 						&info, 4);
 	if (err < 0)
-		goto end;
+		return err;
 
-	/* Timeout means it's invalid request, probably bus reset occurred. */
 	if (wait_for_completion_timeout(&dice->clock_accepted,
-			msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) {
-		if (retries-- == 0) {
-			err = -ETIMEDOUT;
-			goto end;
-		}
+			msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0)
+		return -ETIMEDOUT;
 
-		err = snd_dice_transaction_reinit(dice);
-		if (err < 0)
-			goto end;
-
-		msleep(500);	/* arbitrary */
-		goto retry;
-	}
-end:
-	return err;
+	return 0;
 }
 
 int snd_dice_transaction_get_clock_source(struct snd_dice *dice,
@@ -331,39 +316,60 @@
 	return register_notification_address(dice, false);
 }
 
-int snd_dice_transaction_init(struct snd_dice *dice)
+static int get_subaddrs(struct snd_dice *dice)
 {
-	struct fw_address_handler *handler = &dice->notification_handler;
+	static const int min_values[10] = {
+		10, 0x64 / 4,
+		10, 0x18 / 4,
+		10, 0x18 / 4,
+		0, 0,
+		0, 0,
+	};
 	__be32 *pointers;
+	__be32 version;
+	u32 data;
+	unsigned int i;
 	int err;
 
-	/* Use the same way which dice_interface_check() does. */
-	pointers = kmalloc(sizeof(__be32) * 10, GFP_KERNEL);
+	pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
+				 GFP_KERNEL);
 	if (pointers == NULL)
 		return -ENOMEM;
 
-	/* Get offsets for sub-addresses */
+	/*
+	 * Check that the sub address spaces exist and are located inside the
+	 * private address space.  The minimum values are chosen so that all
+	 * minimally required registers are included.
+	 */
 	err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
-				 DICE_PRIVATE_SPACE,
-				 pointers, sizeof(__be32) * 10, 0);
+				 DICE_PRIVATE_SPACE, pointers,
+				 sizeof(__be32) * ARRAY_SIZE(min_values), 0);
 	if (err < 0)
 		goto end;
 
-	/* Allocation callback in address space over host controller */
-	handler->length = 4;
-	handler->address_callback = dice_notification;
-	handler->callback_data = dice;
-	err = fw_core_add_address_handler(handler, &fw_high_memory_region);
-	if (err < 0) {
-		handler->callback_data = NULL;
-		goto end;
+	for (i = 0; i < ARRAY_SIZE(min_values); ++i) {
+		data = be32_to_cpu(pointers[i]);
+		if (data < min_values[i] || data >= 0x40000) {
+			err = -ENODEV;
+			goto end;
+		}
 	}
 
-	/* Register the address space */
-	err = register_notification_address(dice, true);
-	if (err < 0) {
-		fw_core_remove_address_handler(handler);
-		handler->callback_data = NULL;
+	/*
+	 * Check that the implemented DICE driver specification major version
+	 * number matches.
+	 */
+	err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST,
+				 DICE_PRIVATE_SPACE +
+				 be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
+				 &version, sizeof(version), 0);
+	if (err < 0)
+		goto end;
+
+	if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
+		dev_err(&dice->unit->device,
+			"unknown DICE version: 0x%08x\n", be32_to_cpu(version));
+		err = -ENODEV;
 		goto end;
 	}
 
@@ -380,3 +386,32 @@
 	kfree(pointers);
 	return err;
 }
+
+int snd_dice_transaction_init(struct snd_dice *dice)
+{
+	struct fw_address_handler *handler = &dice->notification_handler;
+	int err;
+
+	err = get_subaddrs(dice);
+	if (err < 0)
+		return err;
+
+	/* Allocation callback in address space over host controller */
+	handler->length = 4;
+	handler->address_callback = dice_notification;
+	handler->callback_data = dice;
+	err = fw_core_add_address_handler(handler, &fw_high_memory_region);
+	if (err < 0) {
+		handler->callback_data = NULL;
+		return err;
+	}
+
+	/* Register the address space */
+	err = register_notification_address(dice, true);
+	if (err < 0) {
+		fw_core_remove_address_handler(handler);
+		handler->callback_data = NULL;
+	}
+
+	return err;
+}
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c
index 0cda05c..b91b373 100644
--- a/sound/firewire/dice/dice.c
+++ b/sound/firewire/dice/dice.c
@@ -18,27 +18,14 @@
 #define WEISS_CATEGORY_ID	0x00
 #define LOUD_CATEGORY_ID	0x10
 
-static int dice_interface_check(struct fw_unit *unit)
+#define PROBE_DELAY_MS		(2 * MSEC_PER_SEC)
+
+static int check_dice_category(struct fw_unit *unit)
 {
-	static const int min_values[10] = {
-		10, 0x64 / 4,
-		10, 0x18 / 4,
-		10, 0x18 / 4,
-		0, 0,
-		0, 0,
-	};
 	struct fw_device *device = fw_parent_device(unit);
 	struct fw_csr_iterator it;
-	int key, val, vendor = -1, model = -1, err;
-	unsigned int category, i;
-	__be32 *pointers;
-	u32 value;
-	__be32 version;
-
-	pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
-				 GFP_KERNEL);
-	if (pointers == NULL)
-		return -ENOMEM;
+	int key, val, vendor = -1, model = -1;
+	unsigned int category;
 
 	/*
 	 * Check that GUID and unit directory are constructed according to DICE
@@ -64,51 +51,10 @@
 	else
 		category = DICE_CATEGORY_ID;
 	if (device->config_rom[3] != ((vendor << 8) | category) ||
-	    device->config_rom[4] >> 22 != model) {
-		err = -ENODEV;
-		goto end;
-	}
+	    device->config_rom[4] >> 22 != model)
+		return -ENODEV;
 
-	/*
-	 * Check that the sub address spaces exist and are located inside the
-	 * private address space.  The minimum values are chosen so that all
-	 * minimally required registers are included.
-	 */
-	err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
-				 DICE_PRIVATE_SPACE, pointers,
-				 sizeof(__be32) * ARRAY_SIZE(min_values), 0);
-	if (err < 0) {
-		err = -ENODEV;
-		goto end;
-	}
-	for (i = 0; i < ARRAY_SIZE(min_values); ++i) {
-		value = be32_to_cpu(pointers[i]);
-		if (value < min_values[i] || value >= 0x40000) {
-			err = -ENODEV;
-			goto end;
-		}
-	}
-
-	/*
-	 * Check that the implemented DICE driver specification major version
-	 * number matches.
-	 */
-	err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
-				 DICE_PRIVATE_SPACE +
-				 be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
-				 &version, 4, 0);
-	if (err < 0) {
-		err = -ENODEV;
-		goto end;
-	}
-	if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
-		dev_err(&unit->device,
-			"unknown DICE version: 0x%08x\n", be32_to_cpu(version));
-		err = -ENODEV;
-		goto end;
-	}
-end:
-	return err;
+	return 0;
 }
 
 static int highest_supported_mode_rate(struct snd_dice *dice,
@@ -231,6 +177,16 @@
 	strcpy(card->mixername, "DICE");
 }
 
+static void dice_free(struct snd_dice *dice)
+{
+	snd_dice_stream_destroy_duplex(dice);
+	snd_dice_transaction_destroy(dice);
+	fw_unit_put(dice->unit);
+
+	mutex_destroy(&dice->mutex);
+	kfree(dice);
+}
+
 /*
  * This module releases the FireWire unit data after all ALSA character devices
  * are released by applications. This is for releasing stream data or finishing
@@ -239,39 +195,21 @@
  */
 static void dice_card_free(struct snd_card *card)
 {
-	struct snd_dice *dice = card->private_data;
-
-	snd_dice_stream_destroy_duplex(dice);
-	snd_dice_transaction_destroy(dice);
-	fw_unit_put(dice->unit);
-
-	mutex_destroy(&dice->mutex);
+	dice_free(card->private_data);
 }
 
-static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
+static void do_registration(struct work_struct *work)
 {
-	struct snd_card *card;
-	struct snd_dice *dice;
+	struct snd_dice *dice = container_of(work, struct snd_dice, dwork.work);
 	int err;
 
-	err = dice_interface_check(unit);
+	if (dice->registered)
+		return;
+
+	err = snd_card_new(&dice->unit->device, -1, NULL, THIS_MODULE, 0,
+			   &dice->card);
 	if (err < 0)
-		goto end;
-
-	err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
-			   sizeof(*dice), &card);
-	if (err < 0)
-		goto end;
-
-	dice = card->private_data;
-	dice->card = card;
-	dice->unit = fw_unit_get(unit);
-	card->private_free = dice_card_free;
-
-	spin_lock_init(&dice->lock);
-	mutex_init(&dice->mutex);
-	init_completion(&dice->clock_accepted);
-	init_waitqueue_head(&dice->hwdep_wait);
+		return;
 
 	err = snd_dice_transaction_init(dice);
 	if (err < 0)
@@ -283,56 +221,131 @@
 
 	dice_card_strings(dice);
 
+	snd_dice_create_proc(dice);
+
 	err = snd_dice_create_pcm(dice);
 	if (err < 0)
 		goto error;
 
+	err = snd_dice_create_midi(dice);
+	if (err < 0)
+		goto error;
+
 	err = snd_dice_create_hwdep(dice);
 	if (err < 0)
 		goto error;
 
-	snd_dice_create_proc(dice);
-
-	err = snd_dice_create_midi(dice);
+	err = snd_card_register(dice->card);
 	if (err < 0)
 		goto error;
 
+	/*
+	 * After registered, dice instance can be released corresponding to
+	 * releasing the sound card instance.
+	 */
+	dice->card->private_free = dice_card_free;
+	dice->card->private_data = dice;
+	dice->registered = true;
+
+	return;
+error:
+	snd_dice_transaction_destroy(dice);
+	snd_card_free(dice->card);
+	dev_info(&dice->unit->device,
+		 "Sound card registration failed: %d\n", err);
+}
+
+static void schedule_registration(struct snd_dice *dice)
+{
+	struct fw_card *fw_card = fw_parent_device(dice->unit)->card;
+	u64 now, delay;
+
+	now = get_jiffies_64();
+	delay = fw_card->reset_jiffies + msecs_to_jiffies(PROBE_DELAY_MS);
+
+	if (time_after64(delay, now))
+		delay -= now;
+	else
+		delay = 0;
+
+	mod_delayed_work(system_wq, &dice->dwork, delay);
+}
+
+static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
+{
+	struct snd_dice *dice;
+	int err;
+
+	err = check_dice_category(unit);
+	if (err < 0)
+		return -ENODEV;
+
+	/* Allocate this independent of sound card instance. */
+	dice = kzalloc(sizeof(struct snd_dice), GFP_KERNEL);
+	if (dice == NULL)
+		return -ENOMEM;
+
+	dice->unit = fw_unit_get(unit);
+	dev_set_drvdata(&unit->device, dice);
+
+	spin_lock_init(&dice->lock);
+	mutex_init(&dice->mutex);
+	init_completion(&dice->clock_accepted);
+	init_waitqueue_head(&dice->hwdep_wait);
+
 	err = snd_dice_stream_init_duplex(dice);
-	if (err < 0)
-		goto error;
-
-	err = snd_card_register(card);
 	if (err < 0) {
-		snd_dice_stream_destroy_duplex(dice);
-		goto error;
+		dice_free(dice);
+		return err;
 	}
 
-	dev_set_drvdata(&unit->device, dice);
-end:
-	return err;
-error:
-	snd_card_free(card);
-	return err;
+	/* Allocate and register this sound card later. */
+	INIT_DEFERRABLE_WORK(&dice->dwork, do_registration);
+	schedule_registration(dice);
+
+	return 0;
 }
 
 static void dice_remove(struct fw_unit *unit)
 {
 	struct snd_dice *dice = dev_get_drvdata(&unit->device);
 
-	/* No need to wait for releasing card object in this context. */
-	snd_card_free_when_closed(dice->card);
+	/*
+	 * Confirm to stop the work for registration before the sound card is
+	 * going to be released. The work is not scheduled again because bus
+	 * reset handler is not called anymore.
+	 */
+	cancel_delayed_work_sync(&dice->dwork);
+
+	if (dice->registered) {
+		/* No need to wait for releasing card object in this context. */
+		snd_card_free_when_closed(dice->card);
+	} else {
+		/* Don't forget this case. */
+		dice_free(dice);
+	}
 }
 
 static void dice_bus_reset(struct fw_unit *unit)
 {
 	struct snd_dice *dice = dev_get_drvdata(&unit->device);
 
+	/* Postpone a workqueue for deferred registration. */
+	if (!dice->registered)
+		schedule_registration(dice);
+
 	/* The handler address register becomes initialized. */
 	snd_dice_transaction_reinit(dice);
 
-	mutex_lock(&dice->mutex);
-	snd_dice_stream_update_duplex(dice);
-	mutex_unlock(&dice->mutex);
+	/*
+	 * After registration, userspace can start packet streaming, then this
+	 * code block works fine.
+	 */
+	if (dice->registered) {
+		mutex_lock(&dice->mutex);
+		snd_dice_stream_update_duplex(dice);
+		mutex_unlock(&dice->mutex);
+	}
 }
 
 #define DICE_INTERFACE	0x000001
diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h
index 101550ac..3d5ebeb 100644
--- a/sound/firewire/dice/dice.h
+++ b/sound/firewire/dice/dice.h
@@ -45,6 +45,9 @@
 	spinlock_t lock;
 	struct mutex mutex;
 
+	bool registered;
+	struct delayed_work dwork;
+
 	/* Offsets for sub-addresses */
 	unsigned int global_offset;
 	unsigned int rx_offset;
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h
index c7cb7de..96c4e0c 100644
--- a/sound/firewire/fireworks/fireworks.h
+++ b/sound/firewire/fireworks/fireworks.h
@@ -86,8 +86,8 @@
 	struct amdtp_stream rx_stream;
 	struct cmp_connection out_conn;
 	struct cmp_connection in_conn;
-	atomic_t capture_substreams;
-	atomic_t playback_substreams;
+	unsigned int capture_substreams;
+	unsigned int playback_substreams;
 
 	/* hardware metering parameters */
 	unsigned int phys_out;
diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c
index fba01bb..3e8c4cf 100644
--- a/sound/firewire/fireworks/fireworks_midi.c
+++ b/sound/firewire/fireworks/fireworks_midi.c
@@ -17,8 +17,10 @@
 	if (err < 0)
 		goto end;
 
-	atomic_inc(&efw->capture_substreams);
+	mutex_lock(&efw->mutex);
+	efw->capture_substreams++;
 	err = snd_efw_stream_start_duplex(efw, 0);
+	mutex_unlock(&efw->mutex);
 	if (err < 0)
 		snd_efw_stream_lock_release(efw);
 
@@ -35,8 +37,10 @@
 	if (err < 0)
 		goto end;
 
-	atomic_inc(&efw->playback_substreams);
+	mutex_lock(&efw->mutex);
+	efw->playback_substreams++;
 	err = snd_efw_stream_start_duplex(efw, 0);
+	mutex_unlock(&efw->mutex);
 	if (err < 0)
 		snd_efw_stream_lock_release(efw);
 end:
@@ -47,8 +51,10 @@
 {
 	struct snd_efw *efw = substream->rmidi->private_data;
 
-	atomic_dec(&efw->capture_substreams);
+	mutex_lock(&efw->mutex);
+	efw->capture_substreams--;
 	snd_efw_stream_stop_duplex(efw);
+	mutex_unlock(&efw->mutex);
 
 	snd_efw_stream_lock_release(efw);
 	return 0;
@@ -58,8 +64,10 @@
 {
 	struct snd_efw *efw = substream->rmidi->private_data;
 
-	atomic_dec(&efw->playback_substreams);
+	mutex_lock(&efw->mutex);
+	efw->playback_substreams--;
 	snd_efw_stream_stop_duplex(efw);
+	mutex_unlock(&efw->mutex);
 
 	snd_efw_stream_lock_release(efw);
 	return 0;
diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c
index d27135b..f4fbf75 100644
--- a/sound/firewire/fireworks/fireworks_pcm.c
+++ b/sound/firewire/fireworks/fireworks_pcm.c
@@ -251,8 +251,11 @@
 	if (err < 0)
 		return err;
 
-	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
-		atomic_inc(&efw->capture_substreams);
+	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+		mutex_lock(&efw->mutex);
+		efw->capture_substreams++;
+		mutex_unlock(&efw->mutex);
+	}
 
 	amdtp_am824_set_pcm_format(&efw->tx_stream, params_format(hw_params));
 
@@ -269,8 +272,11 @@
 	if (err < 0)
 		return err;
 
-	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
-		atomic_inc(&efw->playback_substreams);
+	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+		mutex_lock(&efw->mutex);
+		efw->playback_substreams++;
+		mutex_unlock(&efw->mutex);
+	}
 
 	amdtp_am824_set_pcm_format(&efw->rx_stream, params_format(hw_params));
 
@@ -281,8 +287,11 @@
 {
 	struct snd_efw *efw = substream->private_data;
 
-	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
-		atomic_dec(&efw->capture_substreams);
+	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
+		mutex_lock(&efw->mutex);
+		efw->capture_substreams--;
+		mutex_unlock(&efw->mutex);
+	}
 
 	snd_efw_stream_stop_duplex(efw);
 
@@ -292,8 +301,11 @@
 {
 	struct snd_efw *efw = substream->private_data;
 
-	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
-		atomic_dec(&efw->playback_substreams);
+	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
+		mutex_lock(&efw->mutex);
+		efw->playback_substreams--;
+		mutex_unlock(&efw->mutex);
+	}
 
 	snd_efw_stream_stop_duplex(efw);
 
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c
index 759f6e3..968a40a 100644
--- a/sound/firewire/fireworks/fireworks_stream.c
+++ b/sound/firewire/fireworks/fireworks_stream.c
@@ -209,16 +209,13 @@
 int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate)
 {
 	struct amdtp_stream *master, *slave;
-	atomic_t *slave_substreams;
+	unsigned int slave_substreams;
 	enum cip_flags sync_mode;
 	unsigned int curr_rate;
 	int err = 0;
 
-	mutex_lock(&efw->mutex);
-
 	/* Need no substreams */
-	if ((atomic_read(&efw->playback_substreams) == 0) &&
-	    (atomic_read(&efw->capture_substreams)  == 0))
+	if (efw->playback_substreams == 0 && efw->capture_substreams  == 0)
 		goto end;
 
 	err = get_sync_mode(efw, &sync_mode);
@@ -227,11 +224,11 @@
 	if (sync_mode == CIP_SYNC_TO_DEVICE) {
 		master = &efw->tx_stream;
 		slave  = &efw->rx_stream;
-		slave_substreams  = &efw->playback_substreams;
+		slave_substreams  = efw->playback_substreams;
 	} else {
 		master = &efw->rx_stream;
 		slave  = &efw->tx_stream;
-		slave_substreams = &efw->capture_substreams;
+		slave_substreams = efw->capture_substreams;
 	}
 
 	/*
@@ -277,7 +274,7 @@
 	}
 
 	/* start slave if needed */
-	if (atomic_read(slave_substreams) > 0 && !amdtp_stream_running(slave)) {
+	if (slave_substreams > 0 && !amdtp_stream_running(slave)) {
 		err = start_stream(efw, slave, rate);
 		if (err < 0) {
 			dev_err(&efw->unit->device,
@@ -286,37 +283,32 @@
 		}
 	}
 end:
-	mutex_unlock(&efw->mutex);
 	return err;
 }
 
 void snd_efw_stream_stop_duplex(struct snd_efw *efw)
 {
 	struct amdtp_stream *master, *slave;
-	atomic_t *master_substreams, *slave_substreams;
+	unsigned int master_substreams, slave_substreams;
 
 	if (efw->master == &efw->rx_stream) {
 		slave  = &efw->tx_stream;
 		master = &efw->rx_stream;
-		slave_substreams  = &efw->capture_substreams;
-		master_substreams = &efw->playback_substreams;
+		slave_substreams  = efw->capture_substreams;
+		master_substreams = efw->playback_substreams;
 	} else {
 		slave  = &efw->rx_stream;
 		master = &efw->tx_stream;
-		slave_substreams  = &efw->playback_substreams;
-		master_substreams = &efw->capture_substreams;
+		slave_substreams  = efw->playback_substreams;
+		master_substreams = efw->capture_substreams;
 	}
 
-	mutex_lock(&efw->mutex);
-
-	if (atomic_read(slave_substreams) == 0) {
+	if (slave_substreams == 0) {
 		stop_stream(efw, slave);
 
-		if (atomic_read(master_substreams) == 0)
+		if (master_substreams == 0)
 			stop_stream(efw, master);
 	}
-
-	mutex_unlock(&efw->mutex);
 }
 
 void snd_efw_stream_update_duplex(struct snd_efw *efw)
diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile
index 06ff50f..b474da7 100644
--- a/sound/firewire/oxfw/Makefile
+++ b/sound/firewire/oxfw/Makefile
@@ -1,3 +1,3 @@
-snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-control.o oxfw-pcm.o \
-		 oxfw-proc.o oxfw-midi.o oxfw-hwdep.o oxfw.o
+snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-pcm.o oxfw-proc.o \
+		 oxfw-midi.o oxfw-hwdep.o oxfw-spkr.o oxfw-scs1x.o oxfw.o
 obj-$(CONFIG_SND_OXFW) += snd-oxfw.o
diff --git a/sound/firewire/oxfw/oxfw-control.c b/sound/firewire/oxfw/oxfw-control.c
deleted file mode 100644
index 02a1cb9..0000000
--- a/sound/firewire/oxfw/oxfw-control.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * oxfw_stream.c - a part of driver for OXFW970/971 based devices
- *
- * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
- * Licensed under the terms of the GNU General Public License, version 2.
- */
-
-#include "oxfw.h"
-
-enum control_action { CTL_READ, CTL_WRITE };
-enum control_attribute {
-	CTL_MIN		= 0x02,
-	CTL_MAX		= 0x03,
-	CTL_CURRENT	= 0x10,
-};
-
-static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value,
-			     enum control_action action)
-{
-	u8 *buf;
-	u8 response_ok;
-	int err;
-
-	buf = kmalloc(11, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	if (action == CTL_READ) {
-		buf[0] = 0x01;		/* AV/C, STATUS */
-		response_ok = 0x0c;	/*       STABLE */
-	} else {
-		buf[0] = 0x00;		/* AV/C, CONTROL */
-		response_ok = 0x09;	/*       ACCEPTED */
-	}
-	buf[1] = 0x08;			/* audio unit 0 */
-	buf[2] = 0xb8;			/* FUNCTION BLOCK */
-	buf[3] = 0x81;			/* function block type: feature */
-	buf[4] = oxfw->device_info->mute_fb_id; /* function block ID */
-	buf[5] = 0x10;			/* control attribute: current */
-	buf[6] = 0x02;			/* selector length */
-	buf[7] = 0x00;			/* audio channel number */
-	buf[8] = 0x01;			/* control selector: mute */
-	buf[9] = 0x01;			/* control data length */
-	if (action == CTL_READ)
-		buf[10] = 0xff;
-	else
-		buf[10] = *value ? 0x70 : 0x60;
-
-	err = fcp_avc_transaction(oxfw->unit, buf, 11, buf, 11, 0x3fe);
-	if (err < 0)
-		goto error;
-	if (err < 11) {
-		dev_err(&oxfw->unit->device, "short FCP response\n");
-		err = -EIO;
-		goto error;
-	}
-	if (buf[0] != response_ok) {
-		dev_err(&oxfw->unit->device, "mute command failed\n");
-		err = -EIO;
-		goto error;
-	}
-	if (action == CTL_READ)
-		*value = buf[10] == 0x70;
-
-	err = 0;
-
-error:
-	kfree(buf);
-
-	return err;
-}
-
-static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value,
-			       unsigned int channel,
-			       enum control_attribute attribute,
-			       enum control_action action)
-{
-	u8 *buf;
-	u8 response_ok;
-	int err;
-
-	buf = kmalloc(12, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	if (action == CTL_READ) {
-		buf[0] = 0x01;		/* AV/C, STATUS */
-		response_ok = 0x0c;	/*       STABLE */
-	} else {
-		buf[0] = 0x00;		/* AV/C, CONTROL */
-		response_ok = 0x09;	/*       ACCEPTED */
-	}
-	buf[1] = 0x08;			/* audio unit 0 */
-	buf[2] = 0xb8;			/* FUNCTION BLOCK */
-	buf[3] = 0x81;			/* function block type: feature */
-	buf[4] = oxfw->device_info->volume_fb_id; /* function block ID */
-	buf[5] = attribute;		/* control attribute */
-	buf[6] = 0x02;			/* selector length */
-	buf[7] = channel;		/* audio channel number */
-	buf[8] = 0x02;			/* control selector: volume */
-	buf[9] = 0x02;			/* control data length */
-	if (action == CTL_READ) {
-		buf[10] = 0xff;
-		buf[11] = 0xff;
-	} else {
-		buf[10] = *value >> 8;
-		buf[11] = *value;
-	}
-
-	err = fcp_avc_transaction(oxfw->unit, buf, 12, buf, 12, 0x3fe);
-	if (err < 0)
-		goto error;
-	if (err < 12) {
-		dev_err(&oxfw->unit->device, "short FCP response\n");
-		err = -EIO;
-		goto error;
-	}
-	if (buf[0] != response_ok) {
-		dev_err(&oxfw->unit->device, "volume command failed\n");
-		err = -EIO;
-		goto error;
-	}
-	if (action == CTL_READ)
-		*value = (buf[10] << 8) | buf[11];
-
-	err = 0;
-
-error:
-	kfree(buf);
-
-	return err;
-}
-
-static int oxfw_mute_get(struct snd_kcontrol *control,
-			 struct snd_ctl_elem_value *value)
-{
-	struct snd_oxfw *oxfw = control->private_data;
-
-	value->value.integer.value[0] = !oxfw->mute;
-
-	return 0;
-}
-
-static int oxfw_mute_put(struct snd_kcontrol *control,
-			 struct snd_ctl_elem_value *value)
-{
-	struct snd_oxfw *oxfw = control->private_data;
-	bool mute;
-	int err;
-
-	mute = !value->value.integer.value[0];
-
-	if (mute == oxfw->mute)
-		return 0;
-
-	err = oxfw_mute_command(oxfw, &mute, CTL_WRITE);
-	if (err < 0)
-		return err;
-	oxfw->mute = mute;
-
-	return 1;
-}
-
-static int oxfw_volume_info(struct snd_kcontrol *control,
-			    struct snd_ctl_elem_info *info)
-{
-	struct snd_oxfw *oxfw = control->private_data;
-
-	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	info->count = oxfw->device_info->mixer_channels;
-	info->value.integer.min = oxfw->volume_min;
-	info->value.integer.max = oxfw->volume_max;
-
-	return 0;
-}
-
-static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 };
-
-static int oxfw_volume_get(struct snd_kcontrol *control,
-			   struct snd_ctl_elem_value *value)
-{
-	struct snd_oxfw *oxfw = control->private_data;
-	unsigned int i;
-
-	for (i = 0; i < oxfw->device_info->mixer_channels; ++i)
-		value->value.integer.value[channel_map[i]] = oxfw->volume[i];
-
-	return 0;
-}
-
-static int oxfw_volume_put(struct snd_kcontrol *control,
-			   struct snd_ctl_elem_value *value)
-{
-	struct snd_oxfw *oxfw = control->private_data;
-	unsigned int i, changed_channels;
-	bool equal_values = true;
-	s16 volume;
-	int err;
-
-	for (i = 0; i < oxfw->device_info->mixer_channels; ++i) {
-		if (value->value.integer.value[i] < oxfw->volume_min ||
-		    value->value.integer.value[i] > oxfw->volume_max)
-			return -EINVAL;
-		if (value->value.integer.value[i] !=
-		    value->value.integer.value[0])
-			equal_values = false;
-	}
-
-	changed_channels = 0;
-	for (i = 0; i < oxfw->device_info->mixer_channels; ++i)
-		if (value->value.integer.value[channel_map[i]] !=
-							oxfw->volume[i])
-			changed_channels |= 1 << (i + 1);
-
-	if (equal_values && changed_channels != 0)
-		changed_channels = 1 << 0;
-
-	for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) {
-		volume = value->value.integer.value[channel_map[i ? i - 1 : 0]];
-		if (changed_channels & (1 << i)) {
-			err = oxfw_volume_command(oxfw, &volume, i,
-						   CTL_CURRENT, CTL_WRITE);
-			if (err < 0)
-				return err;
-		}
-		if (i > 0)
-			oxfw->volume[i - 1] = volume;
-	}
-
-	return changed_channels != 0;
-}
-
-int snd_oxfw_create_mixer(struct snd_oxfw *oxfw)
-{
-	static const struct snd_kcontrol_new controls[] = {
-		{
-			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-			.name = "PCM Playback Switch",
-			.info = snd_ctl_boolean_mono_info,
-			.get = oxfw_mute_get,
-			.put = oxfw_mute_put,
-		},
-		{
-			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-			.name = "PCM Playback Volume",
-			.info = oxfw_volume_info,
-			.get = oxfw_volume_get,
-			.put = oxfw_volume_put,
-		},
-	};
-	unsigned int i, first_ch;
-	int err;
-
-	err = oxfw_volume_command(oxfw, &oxfw->volume_min,
-				   0, CTL_MIN, CTL_READ);
-	if (err < 0)
-		return err;
-	err = oxfw_volume_command(oxfw, &oxfw->volume_max,
-				   0, CTL_MAX, CTL_READ);
-	if (err < 0)
-		return err;
-
-	err = oxfw_mute_command(oxfw, &oxfw->mute, CTL_READ);
-	if (err < 0)
-		return err;
-
-	first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1;
-	for (i = 0; i < oxfw->device_info->mixer_channels; ++i) {
-		err = oxfw_volume_command(oxfw, &oxfw->volume[i],
-					   first_ch + i, CTL_CURRENT, CTL_READ);
-		if (err < 0)
-			return err;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(controls); ++i) {
-		err = snd_ctl_add(oxfw->card,
-				  snd_ctl_new1(&controls[i], oxfw));
-		if (err < 0)
-			return err;
-	}
-
-	return 0;
-}
diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c
new file mode 100644
index 0000000..bb53eb3
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-scs1x.c
@@ -0,0 +1,406 @@
+/*
+ * oxfw-scs1x.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Copyright (c) 2015 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+
+#define HSS1394_ADDRESS			0xc007dedadadaULL
+#define HSS1394_MAX_PACKET_SIZE		64
+#define HSS1394_TAG_USER_DATA		0x00
+#define HSS1394_TAG_CHANGE_ADDRESS	0xf1
+
+struct fw_scs1x {
+	struct fw_address_handler hss_handler;
+	u8 input_escape_count;
+	struct snd_rawmidi_substream *input;
+
+	/* For MIDI playback. */
+	struct snd_rawmidi_substream *output;
+	bool output_idle;
+	u8 output_status;
+	u8 output_bytes;
+	bool output_escaped;
+	bool output_escape_high_nibble;
+	struct tasklet_struct tasklet;
+	wait_queue_head_t idle_wait;
+	u8 buffer[HSS1394_MAX_PACKET_SIZE];
+	bool transaction_running;
+	struct fw_transaction transaction;
+	struct fw_device *fw_dev;
+};
+
+static const u8 sysex_escape_prefix[] = {
+	0xf0,			/* SysEx begin */
+	0x00, 0x01, 0x60,	/* Stanton DJ */
+	0x48, 0x53, 0x53,	/* "HSS" */
+};
+
+static void midi_input_escaped_byte(struct snd_rawmidi_substream *stream,
+				    u8 byte)
+{
+	u8 nibbles[2];
+
+	nibbles[0] = byte >> 4;
+	nibbles[1] = byte & 0x0f;
+	snd_rawmidi_receive(stream, nibbles, 2);
+}
+
+static void midi_input_byte(struct fw_scs1x *scs,
+			    struct snd_rawmidi_substream *stream, u8 byte)
+{
+	const u8 eox = 0xf7;
+
+	if (scs->input_escape_count > 0) {
+		midi_input_escaped_byte(stream, byte);
+		scs->input_escape_count--;
+		if (scs->input_escape_count == 0)
+			snd_rawmidi_receive(stream, &eox, sizeof(eox));
+	} else if (byte == 0xf9) {
+		snd_rawmidi_receive(stream, sysex_escape_prefix,
+				    ARRAY_SIZE(sysex_escape_prefix));
+		midi_input_escaped_byte(stream, 0x00);
+		midi_input_escaped_byte(stream, 0xf9);
+		scs->input_escape_count = 3;
+	} else {
+		snd_rawmidi_receive(stream, &byte, 1);
+	}
+}
+
+static void midi_input_packet(struct fw_scs1x *scs,
+			      struct snd_rawmidi_substream *stream,
+			      const u8 *data, unsigned int bytes)
+{
+	unsigned int i;
+	const u8 eox = 0xf7;
+
+	if (data[0] == HSS1394_TAG_USER_DATA) {
+		for (i = 1; i < bytes; ++i)
+			midi_input_byte(scs, stream, data[i]);
+	} else {
+		snd_rawmidi_receive(stream, sysex_escape_prefix,
+				    ARRAY_SIZE(sysex_escape_prefix));
+		for (i = 0; i < bytes; ++i)
+			midi_input_escaped_byte(stream, data[i]);
+		snd_rawmidi_receive(stream, &eox, sizeof(eox));
+	}
+}
+
+static void handle_hss(struct fw_card *card, struct fw_request *request,
+		       int tcode, int destination, int source, int generation,
+		       unsigned long long offset, void *data, size_t length,
+		       void *callback_data)
+{
+	struct fw_scs1x *scs = callback_data;
+	struct snd_rawmidi_substream *stream;
+	int rcode;
+
+	if (offset != scs->hss_handler.offset) {
+		rcode = RCODE_ADDRESS_ERROR;
+		goto end;
+	}
+	if (tcode != TCODE_WRITE_QUADLET_REQUEST &&
+	    tcode != TCODE_WRITE_BLOCK_REQUEST) {
+		rcode = RCODE_TYPE_ERROR;
+		goto end;
+	}
+
+	if (length >= 1) {
+		stream = ACCESS_ONCE(scs->input);
+		if (stream)
+			midi_input_packet(scs, stream, data, length);
+	}
+
+	rcode = RCODE_COMPLETE;
+end:
+	fw_send_response(card, request, rcode);
+}
+
+static void scs_write_callback(struct fw_card *card, int rcode,
+			       void *data, size_t length, void *callback_data)
+{
+	struct fw_scs1x *scs = callback_data;
+
+	if (rcode == RCODE_GENERATION)
+		;	/* TODO: retry this packet */
+
+	scs->transaction_running = false;
+	tasklet_schedule(&scs->tasklet);
+}
+
+static bool is_valid_running_status(u8 status)
+{
+	return status >= 0x80 && status <= 0xef;
+}
+
+static bool is_one_byte_cmd(u8 status)
+{
+	return status == 0xf6 ||
+	       status >= 0xf8;
+}
+
+static bool is_two_bytes_cmd(u8 status)
+{
+	return (status >= 0xc0 && status <= 0xdf) ||
+	       status == 0xf1 ||
+	       status == 0xf3;
+}
+
+static bool is_three_bytes_cmd(u8 status)
+{
+	return (status >= 0x80 && status <= 0xbf) ||
+	       (status >= 0xe0 && status <= 0xef) ||
+	       status == 0xf2;
+}
+
+static bool is_invalid_cmd(u8 status)
+{
+	return status == 0xf4 ||
+	       status == 0xf5 ||
+	       status == 0xf9 ||
+	       status == 0xfd;
+}
+
+static void scs_output_tasklet(unsigned long data)
+{
+	struct fw_scs1x *scs = (struct fw_scs1x *)data;
+	struct snd_rawmidi_substream *stream;
+	unsigned int i;
+	u8 byte;
+	int generation;
+
+	if (scs->transaction_running)
+		return;
+
+	stream = ACCESS_ONCE(scs->output);
+	if (!stream) {
+		scs->output_idle = true;
+		wake_up(&scs->idle_wait);
+		return;
+	}
+
+	i = scs->output_bytes;
+	for (;;) {
+		if (snd_rawmidi_transmit(stream, &byte, 1) != 1) {
+			scs->output_bytes = i;
+			scs->output_idle = true;
+			wake_up(&scs->idle_wait);
+			return;
+		}
+		/*
+		 * Convert from real MIDI to what I think the device expects (no
+		 * running status, one command per packet, unescaped SysExs).
+		 */
+		if (scs->output_escaped && byte < 0x80) {
+			if (scs->output_escape_high_nibble) {
+				if (i < HSS1394_MAX_PACKET_SIZE) {
+					scs->buffer[i] = byte << 4;
+					scs->output_escape_high_nibble = false;
+				}
+			} else {
+				scs->buffer[i++] |= byte & 0x0f;
+				scs->output_escape_high_nibble = true;
+			}
+		} else if (byte < 0x80) {
+			if (i == 1) {
+				if (!is_valid_running_status(
+							scs->output_status))
+					continue;
+				scs->buffer[0] = HSS1394_TAG_USER_DATA;
+				scs->buffer[i++] = scs->output_status;
+			}
+			scs->buffer[i++] = byte;
+			if ((i == 3 && is_two_bytes_cmd(scs->output_status)) ||
+			    (i == 4 && is_three_bytes_cmd(scs->output_status)))
+				break;
+			if (i == 1 + ARRAY_SIZE(sysex_escape_prefix) &&
+			    !memcmp(scs->buffer + 1, sysex_escape_prefix,
+				    ARRAY_SIZE(sysex_escape_prefix))) {
+				scs->output_escaped = true;
+				scs->output_escape_high_nibble = true;
+				i = 0;
+			}
+			if (i >= HSS1394_MAX_PACKET_SIZE)
+				i = 1;
+		} else if (byte == 0xf7) {
+			if (scs->output_escaped) {
+				if (i >= 1 && scs->output_escape_high_nibble &&
+				    scs->buffer[0] !=
+						HSS1394_TAG_CHANGE_ADDRESS)
+					break;
+			} else {
+				if (i > 1 && scs->output_status == 0xf0) {
+					scs->buffer[i++] = 0xf7;
+					break;
+				}
+			}
+			i = 1;
+			scs->output_escaped = false;
+		} else if (!is_invalid_cmd(byte) && byte < 0xf8) {
+			i = 1;
+			scs->buffer[0] = HSS1394_TAG_USER_DATA;
+			scs->buffer[i++] = byte;
+			scs->output_status = byte;
+			scs->output_escaped = false;
+			if (is_one_byte_cmd(byte))
+				break;
+		}
+	}
+	scs->output_bytes = 1;
+	scs->output_escaped = false;
+
+	scs->transaction_running = true;
+	generation = scs->fw_dev->generation;
+	smp_rmb(); /* node_id vs. generation */
+	fw_send_request(scs->fw_dev->card, &scs->transaction,
+			TCODE_WRITE_BLOCK_REQUEST, scs->fw_dev->node_id,
+			generation, scs->fw_dev->max_speed, HSS1394_ADDRESS,
+			scs->buffer, i, scs_write_callback, scs);
+}
+
+static int midi_capture_open(struct snd_rawmidi_substream *stream)
+{
+	return 0;
+}
+
+static int midi_capture_close(struct snd_rawmidi_substream *stream)
+{
+	return 0;
+}
+
+static void midi_capture_trigger(struct snd_rawmidi_substream *stream, int up)
+{
+	struct fw_scs1x *scs = stream->rmidi->private_data;
+
+	if (up) {
+		scs->input_escape_count = 0;
+		ACCESS_ONCE(scs->input) = stream;
+	} else {
+		ACCESS_ONCE(scs->input) = NULL;
+	}
+}
+
+static struct snd_rawmidi_ops midi_capture_ops = {
+	.open    = midi_capture_open,
+	.close   = midi_capture_close,
+	.trigger = midi_capture_trigger,
+};
+
+static int midi_playback_open(struct snd_rawmidi_substream *stream)
+{
+	return 0;
+}
+
+static int midi_playback_close(struct snd_rawmidi_substream *stream)
+{
+	return 0;
+}
+
+static void midi_playback_trigger(struct snd_rawmidi_substream *stream, int up)
+{
+	struct fw_scs1x *scs = stream->rmidi->private_data;
+
+	if (up) {
+		scs->output_status = 0;
+		scs->output_bytes = 1;
+		scs->output_escaped = false;
+		scs->output_idle = false;
+
+		ACCESS_ONCE(scs->output) = stream;
+		tasklet_schedule(&scs->tasklet);
+	} else {
+		ACCESS_ONCE(scs->output) = NULL;
+	}
+}
+static void midi_playback_drain(struct snd_rawmidi_substream *stream)
+{
+	struct fw_scs1x *scs = stream->rmidi->private_data;
+
+	wait_event(scs->idle_wait, scs->output_idle);
+}
+
+static struct snd_rawmidi_ops midi_playback_ops = {
+	.open    = midi_playback_open,
+	.close   = midi_playback_close,
+	.trigger = midi_playback_trigger,
+	.drain   = midi_playback_drain,
+};
+static int register_address(struct snd_oxfw *oxfw)
+{
+	struct fw_scs1x *scs = oxfw->spec;
+	__be64 data;
+
+	data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
+			    scs->hss_handler.offset);
+	return snd_fw_transaction(oxfw->unit, TCODE_WRITE_BLOCK_REQUEST,
+				  HSS1394_ADDRESS, &data, sizeof(data), 0);
+}
+
+static void remove_scs1x(struct snd_rawmidi *rmidi)
+{
+	struct fw_scs1x *scs = rmidi->private_data;
+
+	fw_core_remove_address_handler(&scs->hss_handler);
+}
+
+void snd_oxfw_scs1x_update(struct snd_oxfw *oxfw)
+{
+	register_address(oxfw);
+}
+
+int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw)
+{
+	struct snd_rawmidi *rmidi;
+	struct fw_scs1x *scs;
+	int err;
+
+	scs = kzalloc(sizeof(struct fw_scs1x), GFP_KERNEL);
+	if (scs == NULL)
+		return -ENOMEM;
+	scs->fw_dev = fw_parent_device(oxfw->unit);
+	oxfw->spec = scs;
+
+	/* Allocate own handler for imcoming asynchronous transaction. */
+	scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE;
+	scs->hss_handler.address_callback = handle_hss;
+	scs->hss_handler.callback_data = scs;
+	err = fw_core_add_address_handler(&scs->hss_handler,
+					  &fw_high_memory_region);
+	if (err < 0)
+		return err;
+
+	err = register_address(oxfw);
+	if (err < 0)
+		goto err_allocated;
+
+	/* Use unique name for backward compatibility to scs1x module. */
+	err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 1, 1, &rmidi);
+	if (err < 0)
+		goto err_allocated;
+	rmidi->private_data = scs;
+	rmidi->private_free = remove_scs1x;
+
+	snprintf(rmidi->name, sizeof(rmidi->name),
+		 "%s MIDI", oxfw->card->shortname);
+
+	rmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT |
+			    SNDRV_RAWMIDI_INFO_OUTPUT |
+			    SNDRV_RAWMIDI_INFO_DUPLEX;
+	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+			    &midi_capture_ops);
+	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+			    &midi_playback_ops);
+
+	tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs);
+	init_waitqueue_head(&scs->idle_wait);
+	scs->output_idle = true;
+
+	return 0;
+err_allocated:
+	fw_core_remove_address_handler(&scs->hss_handler);
+	return err;
+}
diff --git a/sound/firewire/oxfw/oxfw-spkr.c b/sound/firewire/oxfw/oxfw-spkr.c
new file mode 100644
index 0000000..cb905af
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-spkr.c
@@ -0,0 +1,319 @@
+/*
+ * oxfw-spkr.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+
+struct fw_spkr {
+	bool mute;
+	s16 volume[6];
+	s16 volume_min;
+	s16 volume_max;
+
+	unsigned int mixer_channels;
+	u8 mute_fb_id;
+	u8 volume_fb_id;
+};
+
+enum control_action { CTL_READ, CTL_WRITE };
+enum control_attribute {
+	CTL_MIN		= 0x02,
+	CTL_MAX		= 0x03,
+	CTL_CURRENT	= 0x10,
+};
+
+static int avc_audio_feature_mute(struct fw_unit *unit, u8 fb_id, bool *value,
+				  enum control_action action)
+{
+	u8 *buf;
+	u8 response_ok;
+	int err;
+
+	buf = kmalloc(11, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (action == CTL_READ) {
+		buf[0] = 0x01;		/* AV/C, STATUS */
+		response_ok = 0x0c;	/*       STABLE */
+	} else {
+		buf[0] = 0x00;		/* AV/C, CONTROL */
+		response_ok = 0x09;	/*       ACCEPTED */
+	}
+	buf[1] = 0x08;			/* audio unit 0 */
+	buf[2] = 0xb8;			/* FUNCTION BLOCK */
+	buf[3] = 0x81;			/* function block type: feature */
+	buf[4] = fb_id;			/* function block ID */
+	buf[5] = 0x10;			/* control attribute: current */
+	buf[6] = 0x02;			/* selector length */
+	buf[7] = 0x00;			/* audio channel number */
+	buf[8] = 0x01;			/* control selector: mute */
+	buf[9] = 0x01;			/* control data length */
+	if (action == CTL_READ)
+		buf[10] = 0xff;
+	else
+		buf[10] = *value ? 0x70 : 0x60;
+
+	err = fcp_avc_transaction(unit, buf, 11, buf, 11, 0x3fe);
+	if (err < 0)
+		goto error;
+	if (err < 11) {
+		dev_err(&unit->device, "short FCP response\n");
+		err = -EIO;
+		goto error;
+	}
+	if (buf[0] != response_ok) {
+		dev_err(&unit->device, "mute command failed\n");
+		err = -EIO;
+		goto error;
+	}
+	if (action == CTL_READ)
+		*value = buf[10] == 0x70;
+
+	err = 0;
+
+error:
+	kfree(buf);
+
+	return err;
+}
+
+static int avc_audio_feature_volume(struct fw_unit *unit, u8 fb_id, s16 *value,
+				    unsigned int channel,
+				    enum control_attribute attribute,
+				    enum control_action action)
+{
+	u8 *buf;
+	u8 response_ok;
+	int err;
+
+	buf = kmalloc(12, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (action == CTL_READ) {
+		buf[0] = 0x01;		/* AV/C, STATUS */
+		response_ok = 0x0c;	/*       STABLE */
+	} else {
+		buf[0] = 0x00;		/* AV/C, CONTROL */
+		response_ok = 0x09;	/*       ACCEPTED */
+	}
+	buf[1] = 0x08;			/* audio unit 0 */
+	buf[2] = 0xb8;			/* FUNCTION BLOCK */
+	buf[3] = 0x81;			/* function block type: feature */
+	buf[4] = fb_id;			/* function block ID */
+	buf[5] = attribute;		/* control attribute */
+	buf[6] = 0x02;			/* selector length */
+	buf[7] = channel;		/* audio channel number */
+	buf[8] = 0x02;			/* control selector: volume */
+	buf[9] = 0x02;			/* control data length */
+	if (action == CTL_READ) {
+		buf[10] = 0xff;
+		buf[11] = 0xff;
+	} else {
+		buf[10] = *value >> 8;
+		buf[11] = *value;
+	}
+
+	err = fcp_avc_transaction(unit, buf, 12, buf, 12, 0x3fe);
+	if (err < 0)
+		goto error;
+	if (err < 12) {
+		dev_err(&unit->device, "short FCP response\n");
+		err = -EIO;
+		goto error;
+	}
+	if (buf[0] != response_ok) {
+		dev_err(&unit->device, "volume command failed\n");
+		err = -EIO;
+		goto error;
+	}
+	if (action == CTL_READ)
+		*value = (buf[10] << 8) | buf[11];
+
+	err = 0;
+
+error:
+	kfree(buf);
+
+	return err;
+}
+
+static int spkr_mute_get(struct snd_kcontrol *control,
+			 struct snd_ctl_elem_value *value)
+{
+	struct snd_oxfw *oxfw = control->private_data;
+	struct fw_spkr *spkr = oxfw->spec;
+
+	value->value.integer.value[0] = !spkr->mute;
+
+	return 0;
+}
+
+static int spkr_mute_put(struct snd_kcontrol *control,
+			 struct snd_ctl_elem_value *value)
+{
+	struct snd_oxfw *oxfw = control->private_data;
+	struct fw_spkr *spkr = oxfw->spec;
+	bool mute;
+	int err;
+
+	mute = !value->value.integer.value[0];
+
+	if (mute == spkr->mute)
+		return 0;
+
+	err = avc_audio_feature_mute(oxfw->unit, spkr->mute_fb_id, &mute,
+				     CTL_WRITE);
+	if (err < 0)
+		return err;
+	spkr->mute = mute;
+
+	return 1;
+}
+
+static int spkr_volume_info(struct snd_kcontrol *control,
+			    struct snd_ctl_elem_info *info)
+{
+	struct snd_oxfw *oxfw = control->private_data;
+	struct fw_spkr *spkr = oxfw->spec;
+
+	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	info->count = spkr->mixer_channels;
+	info->value.integer.min = spkr->volume_min;
+	info->value.integer.max = spkr->volume_max;
+
+	return 0;
+}
+
+static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 };
+
+static int spkr_volume_get(struct snd_kcontrol *control,
+			   struct snd_ctl_elem_value *value)
+{
+	struct snd_oxfw *oxfw = control->private_data;
+	struct fw_spkr *spkr = oxfw->spec;
+	unsigned int i;
+
+	for (i = 0; i < spkr->mixer_channels; ++i)
+		value->value.integer.value[channel_map[i]] = spkr->volume[i];
+
+	return 0;
+}
+
+static int spkr_volume_put(struct snd_kcontrol *control,
+			   struct snd_ctl_elem_value *value)
+{
+	struct snd_oxfw *oxfw = control->private_data;
+	struct fw_spkr *spkr = oxfw->spec;
+	unsigned int i, changed_channels;
+	bool equal_values = true;
+	s16 volume;
+	int err;
+
+	for (i = 0; i < spkr->mixer_channels; ++i) {
+		if (value->value.integer.value[i] < spkr->volume_min ||
+		    value->value.integer.value[i] > spkr->volume_max)
+			return -EINVAL;
+		if (value->value.integer.value[i] !=
+		    value->value.integer.value[0])
+			equal_values = false;
+	}
+
+	changed_channels = 0;
+	for (i = 0; i < spkr->mixer_channels; ++i)
+		if (value->value.integer.value[channel_map[i]] !=
+							spkr->volume[i])
+			changed_channels |= 1 << (i + 1);
+
+	if (equal_values && changed_channels != 0)
+		changed_channels = 1 << 0;
+
+	for (i = 0; i <= spkr->mixer_channels; ++i) {
+		volume = value->value.integer.value[channel_map[i ? i - 1 : 0]];
+		if (changed_channels & (1 << i)) {
+			err = avc_audio_feature_volume(oxfw->unit,
+						  spkr->volume_fb_id, &volume,
+						  i, CTL_CURRENT, CTL_WRITE);
+			if (err < 0)
+				return err;
+		}
+		if (i > 0)
+			spkr->volume[i - 1] = volume;
+	}
+
+	return changed_channels != 0;
+}
+
+int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie)
+{
+	static const struct snd_kcontrol_new controls[] = {
+		{
+			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+			.name = "PCM Playback Switch",
+			.info = snd_ctl_boolean_mono_info,
+			.get = spkr_mute_get,
+			.put = spkr_mute_put,
+		},
+		{
+			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+			.name = "PCM Playback Volume",
+			.info = spkr_volume_info,
+			.get = spkr_volume_get,
+			.put = spkr_volume_put,
+		},
+	};
+	struct fw_spkr *spkr;
+	unsigned int i, first_ch;
+	int err;
+
+	spkr = kzalloc(sizeof(struct fw_spkr), GFP_KERNEL);
+	if (spkr == NULL)
+		return -ENOMEM;
+	oxfw->spec = spkr;
+
+	if (is_lacie) {
+		spkr->mixer_channels = 1;
+		spkr->mute_fb_id = 0x01;
+		spkr->volume_fb_id = 0x01;
+	} else {
+		spkr->mixer_channels = 6;
+		spkr->mute_fb_id = 0x01;
+		spkr->volume_fb_id = 0x02;
+	}
+
+	err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id,
+				       &spkr->volume_min, 0, CTL_MIN, CTL_READ);
+	if (err < 0)
+		return err;
+	err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id,
+				       &spkr->volume_max, 0, CTL_MAX, CTL_READ);
+	if (err < 0)
+		return err;
+
+	err = avc_audio_feature_mute(oxfw->unit, spkr->mute_fb_id, &spkr->mute,
+				     CTL_READ);
+	if (err < 0)
+		return err;
+
+	first_ch = spkr->mixer_channels == 1 ? 0 : 1;
+	for (i = 0; i < spkr->mixer_channels; ++i) {
+		err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id,
+					       &spkr->volume[i], first_ch + i,
+					       CTL_CURRENT, CTL_READ);
+		if (err < 0)
+			return err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(controls); ++i) {
+		err = snd_ctl_add(oxfw->card,
+				  snd_ctl_new1(&controls[i], oxfw));
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
index 588b93f..abedc22 100644
--- a/sound/firewire/oxfw/oxfw.c
+++ b/sound/firewire/oxfw/oxfw.c
@@ -19,6 +19,7 @@
 #define VENDOR_BEHRINGER	0x001564
 #define VENDOR_LACIE		0x00d04b
 #define VENDOR_TASCAM		0x00022e
+#define OUI_STANTON		0x001260
 
 #define MODEL_SATELLITE		0x00200f
 
@@ -29,6 +30,13 @@
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("snd-firewire-speakers");
+MODULE_ALIAS("snd-scs1x");
+
+struct compat_info {
+	const char *driver_name;
+	const char *vendor_name;
+	const char *model_name;
+};
 
 static bool detect_loud_models(struct fw_unit *unit)
 {
@@ -59,6 +67,7 @@
 static int name_card(struct snd_oxfw *oxfw)
 {
 	struct fw_device *fw_dev = fw_parent_device(oxfw->unit);
+	const struct compat_info *info;
 	char vendor[24];
 	char model[32];
 	const char *d, *v, *m;
@@ -84,10 +93,12 @@
 	be32_to_cpus(&firmware);
 
 	/* to apply card definitions */
-	if (oxfw->device_info) {
-		d = oxfw->device_info->driver_name;
-		v = oxfw->device_info->vendor_name;
-		m = oxfw->device_info->model_name;
+	if (oxfw->entry->vendor_id == VENDOR_GRIFFIN ||
+	    oxfw->entry->vendor_id == VENDOR_LACIE) {
+		info = (const struct compat_info *)oxfw->entry->driver_data;
+		d = info->driver_name;
+		v = info->vendor_name;
+		m = info->model_name;
 	} else {
 		d = "OXFW";
 		v = vendor;
@@ -129,16 +140,51 @@
 		kfree(oxfw->rx_stream_formats[i]);
 	}
 
+	kfree(oxfw->spec);
 	mutex_destroy(&oxfw->mutex);
 }
 
-static void detect_quirks(struct snd_oxfw *oxfw)
+static int detect_quirks(struct snd_oxfw *oxfw)
 {
 	struct fw_device *fw_dev = fw_parent_device(oxfw->unit);
 	struct fw_csr_iterator it;
 	int key, val;
 	int vendor, model;
 
+	/*
+	 * Add ALSA control elements for two models to keep compatibility to
+	 * old firewire-speaker module.
+	 */
+	if (oxfw->entry->vendor_id == VENDOR_GRIFFIN)
+		return snd_oxfw_add_spkr(oxfw, false);
+	if (oxfw->entry->vendor_id == VENDOR_LACIE)
+		return snd_oxfw_add_spkr(oxfw, true);
+
+	/*
+	 * Stanton models supports asynchronous transactions for unique MIDI
+	 * messages.
+	 */
+	if (oxfw->entry->vendor_id == OUI_STANTON) {
+		/* No physical MIDI ports. */
+		oxfw->midi_input_ports = 0;
+		oxfw->midi_output_ports = 0;
+
+		/* Output stream exists but no data channels are useful. */
+		oxfw->has_output = false;
+
+		return snd_oxfw_scs1x_add(oxfw);
+	}
+
+	/*
+	 * TASCAM FireOne has physical control and requires a pair of additional
+	 * MIDI ports.
+	 */
+	if (oxfw->entry->vendor_id == VENDOR_TASCAM) {
+		oxfw->midi_input_ports++;
+		oxfw->midi_output_ports++;
+		return 0;
+	}
+
 	/* Seek from Root Directory of Config ROM. */
 	vendor = model = 0;
 	fw_csr_iterator_init(&it, fw_dev->config_rom + 5);
@@ -156,24 +202,17 @@
 	if (vendor == VENDOR_LOUD && model == MODEL_SATELLITE)
 		oxfw->wrong_dbs = true;
 
-	/*
-	 * TASCAM FireOne has physical control and requires a pair of additional
-	 * MIDI ports.
-	 */
-	if (vendor == VENDOR_TASCAM) {
-		oxfw->midi_input_ports++;
-		oxfw->midi_output_ports++;
-	}
+	return 0;
 }
 
 static int oxfw_probe(struct fw_unit *unit,
-		       const struct ieee1394_device_id *id)
+		      const struct ieee1394_device_id *entry)
 {
 	struct snd_card *card;
 	struct snd_oxfw *oxfw;
 	int err;
 
-	if ((id->vendor_id == VENDOR_LOUD) && !detect_loud_models(unit))
+	if (entry->vendor_id == VENDOR_LOUD && !detect_loud_models(unit))
 		return -ENODEV;
 
 	err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
@@ -186,7 +225,7 @@
 	oxfw->card = card;
 	mutex_init(&oxfw->mutex);
 	oxfw->unit = fw_unit_get(unit);
-	oxfw->device_info = (const struct device_info *)id->driver_data;
+	oxfw->entry = entry;
 	spin_lock_init(&oxfw->lock);
 	init_waitqueue_head(&oxfw->hwdep_wait);
 
@@ -194,22 +233,18 @@
 	if (err < 0)
 		goto error;
 
-	detect_quirks(oxfw);
-
 	err = name_card(oxfw);
 	if (err < 0)
 		goto error;
 
+	err = detect_quirks(oxfw);
+	if (err < 0)
+		goto error;
+
 	err = snd_oxfw_create_pcm(oxfw);
 	if (err < 0)
 		goto error;
 
-	if (oxfw->device_info) {
-		err = snd_oxfw_create_mixer(oxfw);
-		if (err < 0)
-			goto error;
-	}
-
 	snd_oxfw_proc_init(oxfw);
 
 	err = snd_oxfw_create_midi(oxfw);
@@ -257,6 +292,9 @@
 		snd_oxfw_stream_update_simplex(oxfw, &oxfw->tx_stream);
 
 	mutex_unlock(&oxfw->mutex);
+
+	if (oxfw->entry->vendor_id == OUI_STANTON)
+		snd_oxfw_scs1x_update(oxfw);
 }
 
 static void oxfw_remove(struct fw_unit *unit)
@@ -267,22 +305,16 @@
 	snd_card_free_when_closed(oxfw->card);
 }
 
-static const struct device_info griffin_firewave = {
+static const struct compat_info griffin_firewave = {
 	.driver_name = "FireWave",
 	.vendor_name = "Griffin",
 	.model_name = "FireWave",
-	.mixer_channels = 6,
-	.mute_fb_id   = 0x01,
-	.volume_fb_id = 0x02,
 };
 
-static const struct device_info lacie_speakers = {
+static const struct compat_info lacie_speakers = {
 	.driver_name = "FWSpeakers",
 	.vendor_name = "LaCie",
 	.model_name = "FireWire Speakers",
-	.mixer_channels = 1,
-	.mute_fb_id   = 0x01,
-	.volume_fb_id = 0x01,
 };
 
 static const struct ieee1394_device_id oxfw_id_table[] = {
@@ -340,6 +372,20 @@
 		.vendor_id	= VENDOR_TASCAM,
 		.model_id	= 0x800007,
 	},
+	/* Stanton, Stanton Controllers & Systems 1 Mixer (SCS.1m) */
+	{
+		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
+				  IEEE1394_MATCH_MODEL_ID,
+		.vendor_id	= OUI_STANTON,
+		.model_id	= 0x001000,
+	},
+	/* Stanton, Stanton Controllers & Systems 1 Deck (SCS.1d) */
+	{
+		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
+				  IEEE1394_MATCH_MODEL_ID,
+		.vendor_id	= OUI_STANTON,
+		.model_id	= 0x002000,
+	},
 	{ }
 };
 MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table);
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h
index 8392c42..9beecc2 100644
--- a/sound/firewire/oxfw/oxfw.h
+++ b/sound/firewire/oxfw/oxfw.h
@@ -31,15 +31,6 @@
 #include "../amdtp-am824.h"
 #include "../cmp.h"
 
-struct device_info {
-	const char *driver_name;
-	const char *vendor_name;
-	const char *model_name;
-	unsigned int mixer_channels;
-	u8 mute_fb_id;
-	u8 volume_fb_id;
-};
-
 /* This is an arbitrary number for convinience. */
 #define	SND_OXFW_STREAM_FORMAT_ENTRIES	10
 struct snd_oxfw {
@@ -64,14 +55,12 @@
 	unsigned int midi_input_ports;
 	unsigned int midi_output_ports;
 
-	bool mute;
-	s16 volume[6];
-	s16 volume_min;
-	s16 volume_max;
-
 	int dev_lock_count;
 	bool dev_lock_changed;
 	wait_queue_head_t hwdep_wait;
+
+	const struct ieee1394_device_id *entry;
+	void *spec;
 };
 
 /*
@@ -138,10 +127,12 @@
 
 int snd_oxfw_create_pcm(struct snd_oxfw *oxfw);
 
-int snd_oxfw_create_mixer(struct snd_oxfw *oxfw);
-
 void snd_oxfw_proc_init(struct snd_oxfw *oxfw);
 
 int snd_oxfw_create_midi(struct snd_oxfw *oxfw);
 
 int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw);
+
+int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie);
+int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw);
+void snd_oxfw_scs1x_update(struct snd_oxfw *oxfw);
diff --git a/sound/firewire/scs1x.c b/sound/firewire/scs1x.c
deleted file mode 100644
index 2dba848..0000000
--- a/sound/firewire/scs1x.c
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Stanton Control System 1 MIDI driver
- *
- * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
- * Licensed under the terms of the GNU General Public License, version 2.
- */
-
-#include <linux/device.h>
-#include <linux/firewire.h>
-#include <linux/firewire-constants.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/wait.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/rawmidi.h>
-#include "lib.h"
-
-#define OUI_STANTON	0x001260
-#define MODEL_SCS_1M	0x001000
-#define MODEL_SCS_1D	0x002000
-
-#define HSS1394_ADDRESS			0xc007dedadadaULL
-#define HSS1394_MAX_PACKET_SIZE		64
-
-#define HSS1394_TAG_USER_DATA		0x00
-#define HSS1394_TAG_CHANGE_ADDRESS	0xf1
-
-struct scs {
-	struct snd_card *card;
-	struct fw_unit *unit;
-	struct fw_address_handler hss_handler;
-	struct fw_transaction transaction;
-	bool transaction_running;
-	bool output_idle;
-	u8 output_status;
-	u8 output_bytes;
-	bool output_escaped;
-	bool output_escape_high_nibble;
-	u8 input_escape_count;
-	struct snd_rawmidi_substream *output;
-	struct snd_rawmidi_substream *input;
-	struct tasklet_struct tasklet;
-	wait_queue_head_t idle_wait;
-	u8 *buffer;
-};
-
-static const u8 sysex_escape_prefix[] = {
-	0xf0,			/* SysEx begin */
-	0x00, 0x01, 0x60,	/* Stanton DJ */
-	0x48, 0x53, 0x53,	/* "HSS" */
-};
-
-static int scs_output_open(struct snd_rawmidi_substream *stream)
-{
-	struct scs *scs = stream->rmidi->private_data;
-
-	scs->output_status = 0;
-	scs->output_bytes = 1;
-	scs->output_escaped = false;
-
-	return 0;
-}
-
-static int scs_output_close(struct snd_rawmidi_substream *stream)
-{
-	return 0;
-}
-
-static void scs_output_trigger(struct snd_rawmidi_substream *stream, int up)
-{
-	struct scs *scs = stream->rmidi->private_data;
-
-	ACCESS_ONCE(scs->output) = up ? stream : NULL;
-	if (up) {
-		scs->output_idle = false;
-		tasklet_schedule(&scs->tasklet);
-	}
-}
-
-static void scs_write_callback(struct fw_card *card, int rcode,
-			       void *data, size_t length, void *callback_data)
-{
-	struct scs *scs = callback_data;
-
-	if (rcode == RCODE_GENERATION) {
-		/* TODO: retry this packet */
-	}
-
-	scs->transaction_running = false;
-	tasklet_schedule(&scs->tasklet);
-}
-
-static bool is_valid_running_status(u8 status)
-{
-	return status >= 0x80 && status <= 0xef;
-}
-
-static bool is_one_byte_cmd(u8 status)
-{
-	return status == 0xf6 ||
-	       status >= 0xf8;
-}
-
-static bool is_two_bytes_cmd(u8 status)
-{
-	return (status >= 0xc0 && status <= 0xdf) ||
-	       status == 0xf1 ||
-	       status == 0xf3;
-}
-
-static bool is_three_bytes_cmd(u8 status)
-{
-	return (status >= 0x80 && status <= 0xbf) ||
-	       (status >= 0xe0 && status <= 0xef) ||
-	       status == 0xf2;
-}
-
-static bool is_invalid_cmd(u8 status)
-{
-	return status == 0xf4 ||
-	       status == 0xf5 ||
-	       status == 0xf9 ||
-	       status == 0xfd;
-}
-
-static void scs_output_tasklet(unsigned long data)
-{
-	struct scs *scs = (void *)data;
-	struct snd_rawmidi_substream *stream;
-	unsigned int i;
-	u8 byte;
-	struct fw_device *dev;
-	int generation;
-
-	if (scs->transaction_running)
-		return;
-
-	stream = ACCESS_ONCE(scs->output);
-	if (!stream) {
-		scs->output_idle = true;
-		wake_up(&scs->idle_wait);
-		return;
-	}
-
-	i = scs->output_bytes;
-	for (;;) {
-		if (snd_rawmidi_transmit(stream, &byte, 1) != 1) {
-			scs->output_bytes = i;
-			scs->output_idle = true;
-			wake_up(&scs->idle_wait);
-			return;
-		}
-		/*
-		 * Convert from real MIDI to what I think the device expects (no
-		 * running status, one command per packet, unescaped SysExs).
-		 */
-		if (scs->output_escaped && byte < 0x80) {
-			if (scs->output_escape_high_nibble) {
-				if (i < HSS1394_MAX_PACKET_SIZE) {
-					scs->buffer[i] = byte << 4;
-					scs->output_escape_high_nibble = false;
-				}
-			} else {
-				scs->buffer[i++] |= byte & 0x0f;
-				scs->output_escape_high_nibble = true;
-			}
-		} else if (byte < 0x80) {
-			if (i == 1) {
-				if (!is_valid_running_status(scs->output_status))
-					continue;
-				scs->buffer[0] = HSS1394_TAG_USER_DATA;
-				scs->buffer[i++] = scs->output_status;
-			}
-			scs->buffer[i++] = byte;
-			if ((i == 3 && is_two_bytes_cmd(scs->output_status)) ||
-			    (i == 4 && is_three_bytes_cmd(scs->output_status)))
-				break;
-			if (i == 1 + ARRAY_SIZE(sysex_escape_prefix) &&
-			    !memcmp(scs->buffer + 1, sysex_escape_prefix,
-				    ARRAY_SIZE(sysex_escape_prefix))) {
-				scs->output_escaped = true;
-				scs->output_escape_high_nibble = true;
-				i = 0;
-			}
-			if (i >= HSS1394_MAX_PACKET_SIZE)
-				i = 1;
-		} else if (byte == 0xf7) {
-			if (scs->output_escaped) {
-				if (i >= 1 && scs->output_escape_high_nibble &&
-				    scs->buffer[0] != HSS1394_TAG_CHANGE_ADDRESS)
-					break;
-			} else {
-				if (i > 1 && scs->output_status == 0xf0) {
-					scs->buffer[i++] = 0xf7;
-					break;
-				}
-			}
-			i = 1;
-			scs->output_escaped = false;
-		} else if (!is_invalid_cmd(byte) &&
-			   byte < 0xf8) {
-			i = 1;
-			scs->buffer[0] = HSS1394_TAG_USER_DATA;
-			scs->buffer[i++] = byte;
-			scs->output_status = byte;
-			scs->output_escaped = false;
-			if (is_one_byte_cmd(byte))
-				break;
-		}
-	}
-	scs->output_bytes = 1;
-	scs->output_escaped = false;
-
-	scs->transaction_running = true;
-	dev = fw_parent_device(scs->unit);
-	generation = dev->generation;
-	smp_rmb(); /* node_id vs. generation */
-	fw_send_request(dev->card, &scs->transaction, TCODE_WRITE_BLOCK_REQUEST,
-			dev->node_id, generation, dev->max_speed,
-			HSS1394_ADDRESS, scs->buffer, i,
-			scs_write_callback, scs);
-}
-
-static void scs_output_drain(struct snd_rawmidi_substream *stream)
-{
-	struct scs *scs = stream->rmidi->private_data;
-
-	wait_event(scs->idle_wait, scs->output_idle);
-}
-
-static struct snd_rawmidi_ops output_ops = {
-	.open    = scs_output_open,
-	.close   = scs_output_close,
-	.trigger = scs_output_trigger,
-	.drain   = scs_output_drain,
-};
-
-static int scs_input_open(struct snd_rawmidi_substream *stream)
-{
-	struct scs *scs = stream->rmidi->private_data;
-
-	scs->input_escape_count = 0;
-
-	return 0;
-}
-
-static int scs_input_close(struct snd_rawmidi_substream *stream)
-{
-	return 0;
-}
-
-static void scs_input_trigger(struct snd_rawmidi_substream *stream, int up)
-{
-	struct scs *scs = stream->rmidi->private_data;
-
-	ACCESS_ONCE(scs->input) = up ? stream : NULL;
-}
-
-static void scs_input_escaped_byte(struct snd_rawmidi_substream *stream,
-				   u8 byte)
-{
-	u8 nibbles[2];
-
-	nibbles[0] = byte >> 4;
-	nibbles[1] = byte & 0x0f;
-	snd_rawmidi_receive(stream, nibbles, 2);
-}
-
-static void scs_input_midi_byte(struct scs *scs,
-				struct snd_rawmidi_substream *stream,
-				u8 byte)
-{
-	if (scs->input_escape_count > 0) {
-		scs_input_escaped_byte(stream, byte);
-		scs->input_escape_count--;
-		if (scs->input_escape_count == 0)
-			snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1);
-	} else if (byte == 0xf9) {
-		snd_rawmidi_receive(stream, sysex_escape_prefix,
-				    ARRAY_SIZE(sysex_escape_prefix));
-		scs_input_escaped_byte(stream, 0x00);
-		scs_input_escaped_byte(stream, 0xf9);
-		scs->input_escape_count = 3;
-	} else {
-		snd_rawmidi_receive(stream, &byte, 1);
-	}
-}
-
-static void scs_input_packet(struct scs *scs,
-			     struct snd_rawmidi_substream *stream,
-			     const u8 *data, unsigned int bytes)
-{
-	unsigned int i;
-
-	if (data[0] == HSS1394_TAG_USER_DATA) {
-		for (i = 1; i < bytes; ++i)
-			scs_input_midi_byte(scs, stream, data[i]);
-	} else {
-		snd_rawmidi_receive(stream, sysex_escape_prefix,
-				    ARRAY_SIZE(sysex_escape_prefix));
-		for (i = 0; i < bytes; ++i)
-			scs_input_escaped_byte(stream, data[i]);
-		snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1);
-	}
-}
-
-static struct snd_rawmidi_ops input_ops = {
-	.open    = scs_input_open,
-	.close   = scs_input_close,
-	.trigger = scs_input_trigger,
-};
-
-static int scs_create_midi(struct scs *scs)
-{
-	struct snd_rawmidi *rmidi;
-	int err;
-
-	err = snd_rawmidi_new(scs->card, "SCS.1x", 0, 1, 1, &rmidi);
-	if (err < 0)
-		return err;
-	snprintf(rmidi->name, sizeof(rmidi->name),
-		 "%s MIDI", scs->card->shortname);
-	rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
-	                    SNDRV_RAWMIDI_INFO_INPUT |
-	                    SNDRV_RAWMIDI_INFO_DUPLEX;
-	rmidi->private_data = scs;
-	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &output_ops);
-	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &input_ops);
-
-	return 0;
-}
-
-static void handle_hss(struct fw_card *card, struct fw_request *request,
-		       int tcode, int destination, int source, int generation,
-		       unsigned long long offset, void *data, size_t length,
-		       void *callback_data)
-{
-	struct scs *scs = callback_data;
-	struct snd_rawmidi_substream *stream;
-
-	if (offset != scs->hss_handler.offset) {
-		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
-		return;
-	}
-	if (tcode != TCODE_WRITE_QUADLET_REQUEST &&
-	    tcode != TCODE_WRITE_BLOCK_REQUEST) {
-		fw_send_response(card, request, RCODE_TYPE_ERROR);
-		return;
-	}
-
-	if (length >= 1) {
-		stream = ACCESS_ONCE(scs->input);
-		if (stream)
-			scs_input_packet(scs, stream, data, length);
-	}
-
-	fw_send_response(card, request, RCODE_COMPLETE);
-}
-
-static int scs_init_hss_address(struct scs *scs)
-{
-	__be64 data;
-	int err;
-
-	data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
-			   scs->hss_handler.offset);
-	err = snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST,
-				 HSS1394_ADDRESS, &data, 8, 0);
-	if (err < 0)
-		dev_err(&scs->unit->device, "HSS1394 communication failed\n");
-
-	return err;
-}
-
-static void scs_card_free(struct snd_card *card)
-{
-	struct scs *scs = card->private_data;
-
-	fw_core_remove_address_handler(&scs->hss_handler);
-	kfree(scs->buffer);
-}
-
-static int scs_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
-{
-	struct fw_device *fw_dev = fw_parent_device(unit);
-	struct snd_card *card;
-	struct scs *scs;
-	int err;
-
-	err = snd_card_new(&unit->device, -16, NULL, THIS_MODULE,
-			   sizeof(*scs), &card);
-	if (err < 0)
-		return err;
-
-	scs = card->private_data;
-	scs->card = card;
-	scs->unit = unit;
-	tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs);
-	init_waitqueue_head(&scs->idle_wait);
-	scs->output_idle = true;
-
-	scs->buffer = kmalloc(HSS1394_MAX_PACKET_SIZE, GFP_KERNEL);
-	if (!scs->buffer) {
-		err = -ENOMEM;
-		goto err_card;
-	}
-
-	scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE;
-	scs->hss_handler.address_callback = handle_hss;
-	scs->hss_handler.callback_data = scs;
-	err = fw_core_add_address_handler(&scs->hss_handler,
-					  &fw_high_memory_region);
-	if (err < 0)
-		goto err_buffer;
-
-	card->private_free = scs_card_free;
-
-	strcpy(card->driver, "SCS.1x");
-	strcpy(card->shortname, "SCS.1x");
-	fw_csr_string(unit->directory, CSR_MODEL,
-		      card->shortname, sizeof(card->shortname));
-	snprintf(card->longname, sizeof(card->longname),
-		 "Stanton DJ %s (GUID %08x%08x) at %s, S%d",
-		 card->shortname, fw_dev->config_rom[3], fw_dev->config_rom[4],
-		 dev_name(&unit->device), 100 << fw_dev->max_speed);
-	strcpy(card->mixername, card->shortname);
-
-	err = scs_init_hss_address(scs);
-	if (err < 0)
-		goto err_card;
-
-	err = scs_create_midi(scs);
-	if (err < 0)
-		goto err_card;
-
-	err = snd_card_register(card);
-	if (err < 0)
-		goto err_card;
-
-	dev_set_drvdata(&unit->device, scs);
-
-	return 0;
-
-err_buffer:
-	kfree(scs->buffer);
-err_card:
-	snd_card_free(card);
-	return err;
-}
-
-static void scs_update(struct fw_unit *unit)
-{
-	struct scs *scs = dev_get_drvdata(&unit->device);
-	int generation;
-	__be64 data;
-
-	data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
-			   scs->hss_handler.offset);
-	generation = fw_parent_device(unit)->generation;
-	smp_rmb(); /* node_id vs. generation */
-	snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST,
-			   HSS1394_ADDRESS, &data, 8,
-			   FW_FIXED_GENERATION | generation);
-}
-
-static void scs_remove(struct fw_unit *unit)
-{
-	struct scs *scs = dev_get_drvdata(&unit->device);
-
-	snd_card_disconnect(scs->card);
-
-	ACCESS_ONCE(scs->output) = NULL;
-	ACCESS_ONCE(scs->input) = NULL;
-
-	wait_event(scs->idle_wait, scs->output_idle);
-
-	tasklet_kill(&scs->tasklet);
-
-	snd_card_free_when_closed(scs->card);
-}
-
-static const struct ieee1394_device_id scs_id_table[] = {
-	{
-		.match_flags = IEEE1394_MATCH_VENDOR_ID |
-		               IEEE1394_MATCH_MODEL_ID,
-		.vendor_id   = OUI_STANTON,
-		.model_id    = MODEL_SCS_1M,
-	},
-	{
-		.match_flags = IEEE1394_MATCH_VENDOR_ID |
-		               IEEE1394_MATCH_MODEL_ID,
-		.vendor_id   = OUI_STANTON,
-		.model_id    = MODEL_SCS_1D,
-	},
-	{}
-};
-MODULE_DEVICE_TABLE(ieee1394, scs_id_table);
-
-MODULE_DESCRIPTION("SCS.1x MIDI driver");
-MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_LICENSE("GPL v2");
-
-static struct fw_driver scs_driver = {
-	.driver = {
-		.owner  = THIS_MODULE,
-		.name   = KBUILD_MODNAME,
-		.bus    = &fw_bus_type,
-	},
-	.probe    = scs_probe,
-	.update   = scs_update,
-	.remove   = scs_remove,
-	.id_table = scs_id_table,
-};
-
-static int __init alsa_scs1x_init(void)
-{
-	return driver_register(&scs_driver.driver);
-}
-
-static void __exit alsa_scs1x_exit(void)
-{
-	driver_unregister(&scs_driver.driver);
-}
-
-module_init(alsa_scs1x_init);
-module_exit(alsa_scs1x_exit);
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c
index 63215b1..548cc1e 100644
--- a/sound/hda/ext/hdac_ext_controller.c
+++ b/sound/hda/ext/hdac_ext_controller.c
@@ -77,6 +77,12 @@
 			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;
@@ -240,7 +246,7 @@
 	int mask = (1 << AZX_MLCTL_CPA);
 
 	udelay(3);
-	timeout = 50;
+	timeout = 150;
 
 	do {
 		val = readl(link->ml_addr + AZX_REG_ML_LCTL);
@@ -282,6 +288,27 @@
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down);
 
 /**
+ * snd_hdac_ext_bus_link_power_up_all -power up all hda link
+ * @ebus: HD-audio extended bus
+ */
+int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus)
+{
+	struct hdac_ext_link *hlink = NULL;
+	int ret;
+
+	list_for_each_entry(hlink, &ebus->hlink_list, list) {
+		snd_hdac_updatel(hlink->ml_addr,
+				AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
+		ret = check_hdac_link_power_active(hlink, true);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up_all);
+
+/**
  * snd_hdac_ext_bus_link_power_down_all -power down all hda link
  * @ebus: HD-audio extended bus
  */
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c
index cb89ec7..023cc4c 100644
--- a/sound/hda/ext/hdac_ext_stream.c
+++ b/sound/hda/ext/hdac_ext_stream.c
@@ -59,6 +59,10 @@
 					AZX_SPB_MAXFIFO;
 	}
 
+	if (ebus->drsmcap)
+		stream->dpibr_addr = ebus->drsmcap + AZX_DRSM_BASE +
+					AZX_DRSM_INTERVAL * idx;
+
 	stream->decoupled = false;
 	snd_hdac_stream_init(bus, &stream->hstream, idx, direction, tag);
 }
@@ -107,6 +111,7 @@
 	while (!list_empty(&bus->stream_list)) {
 		s = list_first_entry(&bus->stream_list, struct hdac_stream, list);
 		stream = stream_to_hdac_ext_stream(s);
+		snd_hdac_ext_stream_decouple(ebus, stream, false);
 		list_del(&s->list);
 		kfree(stream);
 	}
@@ -497,3 +502,70 @@
 	}
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_stop_streams);
+
+/**
+ * snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream
+ * @ebus: HD-audio ext core bus
+ * @enable: flag to enable/disable DRSM
+ * @index: stream index for which DRSM need to be enabled
+ */
+void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
+				bool enable, int index)
+{
+	u32 mask = 0;
+	u32 register_mask = 0;
+	struct hdac_bus *bus = &ebus->bus;
+
+	if (!ebus->drsmcap) {
+		dev_err(bus->dev, "Address of DRSM capability is NULL");
+		return;
+	}
+
+	mask |= (1 << index);
+
+	register_mask = readl(ebus->drsmcap + AZX_REG_SPB_SPBFCCTL);
+
+	mask |= register_mask;
+
+	if (enable)
+		snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, 0, mask);
+	else
+		snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable);
+
+/**
+ * snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream
+ * @ebus: HD-audio ext core bus
+ * @stream: hdac_ext_stream
+ * @value: dpib value to set
+ */
+int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
+				 struct hdac_ext_stream *stream, u32 value)
+{
+	struct hdac_bus *bus = &ebus->bus;
+
+	if (!ebus->drsmcap) {
+		dev_err(bus->dev, "Address of DRSM capability is NULL");
+		return -EINVAL;
+	}
+
+	writel(value, stream->dpibr_addr);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr);
+
+/**
+ * snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream
+ * @ebus: HD-audio ext core bus
+ * @stream: hdac_ext_stream
+ * @value: lpib value to set
+ */
+int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value)
+{
+	snd_hdac_stream_writel(&stream->hstream, SD_LPIB, value);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib);
diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c
index 8fef1b8..c50177f 100644
--- a/sound/hda/hdac_i915.c
+++ b/sound/hda/hdac_i915.c
@@ -118,6 +118,72 @@
 }
 EXPORT_SYMBOL_GPL(snd_hdac_get_display_clk);
 
+/* There is a fixed mapping between audio pin node and display port
+ * on current Intel platforms:
+ * Pin Widget 5 - PORT B (port = 1 in i915 driver)
+ * Pin Widget 6 - PORT C (port = 2 in i915 driver)
+ * Pin Widget 7 - PORT D (port = 3 in i915 driver)
+ */
+static int pin2port(hda_nid_t pin_nid)
+{
+	return pin_nid - 4;
+}
+
+/**
+ * snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate
+ * @bus: HDA core bus
+ * @nid: the pin widget NID
+ * @rate: the sample rate to set
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with i915 graphics.
+ *
+ * This function sets N/CTS value based on the given sample rate.
+ * Returns zero for success, or a negative error code.
+ */
+int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, int rate)
+{
+	struct i915_audio_component *acomp = bus->audio_component;
+
+	if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
+		return -ENODEV;
+	return acomp->ops->sync_audio_rate(acomp->dev, pin2port(nid), rate);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
+
+/**
+ * snd_hdac_acomp_get_eld - Get the audio state and ELD via component
+ * @bus: HDA core bus
+ * @nid: the pin widget NID
+ * @audio_enabled: the pointer to store the current audio state
+ * @buffer: the buffer pointer to store ELD bytes
+ * @max_bytes: the max bytes to be stored on @buffer
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with i915 graphics.
+ *
+ * This function queries the current state of the audio on the given
+ * digital port and fetches the ELD bytes onto the given buffer.
+ * It returns the number of bytes for the total ELD data, zero for
+ * invalid ELD, or a negative error code.
+ *
+ * The return size is the total bytes required for the whole ELD bytes,
+ * thus it may be over @max_bytes.  If it's over @max_bytes, it implies
+ * that only a part of ELD bytes have been fetched.
+ */
+int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid,
+			   bool *audio_enabled, char *buffer, int max_bytes)
+{
+	struct i915_audio_component *acomp = bus->audio_component;
+
+	if (!acomp || !acomp->ops || !acomp->ops->get_eld)
+		return -ENODEV;
+
+	return acomp->ops->get_eld(acomp->dev, pin2port(nid), audio_enabled,
+				   buffer, max_bytes);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
+
 static int hdac_component_master_bind(struct device *dev)
 {
 	struct i915_audio_component *acomp = hdac_acomp;
diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c
index 4677037..ef2a9af 100644
--- a/sound/i2c/i2c.c
+++ b/sound/i2c/i2c.c
@@ -39,7 +39,7 @@
 static int snd_i2c_bit_probeaddr(struct snd_i2c_bus *bus,
 				 unsigned short addr);
 
-static struct snd_i2c_ops snd_i2c_bit_ops = {
+static const struct snd_i2c_ops snd_i2c_bit_ops = {
 	.sendbytes = snd_i2c_bit_sendbytes,
 	.readbytes = snd_i2c_bit_readbytes,
 	.probeaddr = snd_i2c_bit_probeaddr,
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 48568fd..4033fe5 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -240,7 +240,7 @@
 
 menuconfig SOUND_OSS
 	tristate "OSS sound modules"
-	depends on ISA_DMA_API && VIRT_TO_BUS
+	depends on ISA_DMA_API && (VIRT_TO_BUS || ARCH_RPC || ARCH_NETWINDER)
 	depends on !GENERIC_ISA_DMA_SUPPORT_BROKEN
 	help
 	  OSS is the Open Sound System suite of sound card drivers.  They make
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 1028fc8..2ce0022 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -1219,7 +1219,7 @@
 	},
 };
 
-static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = {
+static const struct atiixp_dma_ops snd_atiixp_playback_dma_ops = {
 	.type = ATI_DMA_PLAYBACK,
 	.llp_offset = ATI_REG_OUT_DMA_LINKPTR,
 	.dt_cur = ATI_REG_OUT_DMA_DT_CUR,
@@ -1228,7 +1228,7 @@
 	.flush_dma = atiixp_out_flush_dma,
 };
 	
-static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = {
+static const struct atiixp_dma_ops snd_atiixp_capture_dma_ops = {
 	.type = ATI_DMA_CAPTURE,
 	.llp_offset = ATI_REG_IN_DMA_LINKPTR,
 	.dt_cur = ATI_REG_IN_DMA_DT_CUR,
@@ -1237,7 +1237,7 @@
 	.flush_dma = atiixp_in_flush_dma,
 };
 	
-static struct atiixp_dma_ops snd_atiixp_spdif_dma_ops = {
+static const struct atiixp_dma_ops snd_atiixp_spdif_dma_ops = {
 	.type = ATI_DMA_SPDIF,
 	.llp_offset = ATI_REG_SPDF_DMA_LINKPTR,
 	.dt_cur = ATI_REG_SPDF_DMA_DT_CUR,
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 27ed678..c534552 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -970,7 +970,7 @@
 	.pointer =	snd_atiixp_pcm_pointer,
 };
 
-static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = {
+static const struct atiixp_dma_ops snd_atiixp_playback_dma_ops = {
 	.type = ATI_DMA_PLAYBACK,
 	.llp_offset = ATI_REG_MODEM_OUT_DMA1_LINKPTR,
 	.dt_cur = ATI_REG_MODEM_OUT_DMA1_DT_CUR,
@@ -979,7 +979,7 @@
 	.flush_dma = atiixp_out_flush_dma,
 };
 	
-static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = {
+static const struct atiixp_dma_ops snd_atiixp_capture_dma_ops = {
 	.type = ATI_DMA_CAPTURE,
 	.llp_offset = ATI_REG_MODEM_IN_DMA_LINKPTR,
 	.dt_cur = ATI_REG_MODEM_IN_DMA_DT_CUR,
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 07a4acc..5e2ef0b 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -2294,8 +2294,6 @@
 	snd_azf3328_timer_stop(chip->timer);
 	snd_azf3328_gameport_free(chip);
 
-	if (chip->irq >= 0)
-		synchronize_irq(chip->irq);
 __end_hw:
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c
index 9c2dc91..27fa57d 100644
--- a/sound/pci/cs5535audio/cs5535audio_pcm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pcm.c
@@ -402,7 +402,7 @@
 	.pointer =	snd_cs5535audio_pcm_pointer,
 };
 
-static struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = {
+static const struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = {
         .type = CS5535AUDIO_DMA_PLAYBACK,
         .enable_dma = cs5535audio_playback_enable_dma,
         .disable_dma = cs5535audio_playback_disable_dma,
@@ -412,7 +412,7 @@
         .read_dma_pntr = cs5535audio_playback_read_dma_pntr,
 };
 
-static struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = {
+static const struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = {
         .type = CS5535AUDIO_DMA_CAPTURE,
         .enable_dma = cs5535audio_capture_enable_dma,
         .disable_dma = cs5535audio_capture_disable_dma,
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 759295a..bade9b9 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -163,6 +163,7 @@
  * @cap_ctrl:		capture control
  */
 struct fm801 {
+	struct device *dev;
 	int irq;
 
 	unsigned long port;
@@ -190,7 +191,6 @@
 	struct snd_ac97 *ac97;
 	struct snd_ac97 *ac97_sec;
 
-	struct pci_dev *pci;
 	struct snd_card *card;
 	struct snd_pcm *pcm;
 	struct snd_rawmidi *rmidi;
@@ -212,6 +212,20 @@
 #endif
 };
 
+/*
+ * IO accessors
+ */
+
+static inline void fm801_iowrite16(struct fm801 *chip, unsigned short offset, u16 value)
+{
+	outw(value, chip->port + offset);
+}
+
+static inline u16 fm801_ioread16(struct fm801 *chip, unsigned short offset)
+{
+	return inw(chip->port + offset);
+}
+
 static const struct pci_device_id snd_fm801_ids[] = {
 	{ 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, },   /* FM801 */
 	{ 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, },   /* Gallant Odyssey Sound 4 */
@@ -256,11 +270,11 @@
 	unsigned short old, new;
 
 	spin_lock_irqsave(&chip->reg_lock, flags);
-	old = inw(chip->port + reg);
+	old = fm801_ioread16(chip, reg);
 	new = (old & ~mask) | value;
 	change = old != new;
 	if (change)
-		outw(new, chip->port + reg);
+		fm801_iowrite16(chip, reg, new);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 	return change;
 }
@@ -578,8 +592,9 @@
 	}
 	if (chip->rmidi && (status & FM801_IRQ_MPU))
 		snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
-	if (status & FM801_IRQ_VOLUME)
-		;/* TODO */
+	if (status & FM801_IRQ_VOLUME) {
+		/* TODO */
+	}
 
 	return IRQ_HANDLED;
 }
@@ -700,6 +715,7 @@
 
 static int snd_fm801_pcm(struct fm801 *chip, int device)
 {
+	struct pci_dev *pdev = to_pci_dev(chip->dev);
 	struct snd_pcm *pcm;
 	int err;
 
@@ -715,7 +731,7 @@
 	chip->pcm = pcm;
 
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-					      snd_dma_pci_data(chip->pci),
+					      snd_dma_pci_data(pdev),
 					      chip->multichannel ? 128*1024 : 64*1024, 128*1024);
 
 	return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
@@ -851,10 +867,11 @@
 	int shift = (kcontrol->private_value >> 8) & 0xff;
 	int mask = (kcontrol->private_value >> 16) & 0xff;
 	int invert = (kcontrol->private_value >> 24) & 0xff;
+	long *value = ucontrol->value.integer.value;
 
-	ucontrol->value.integer.value[0] = (inw(chip->port + reg) >> shift) & mask;
+	value[0] = (fm801_ioread16(chip, reg) >> shift) & mask;
 	if (invert)
-		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
+		value[0] = mask - value[0];
 	return 0;
 }
 
@@ -907,14 +924,15 @@
 	int shift_right = (kcontrol->private_value >> 12) & 0x0f;
 	int mask = (kcontrol->private_value >> 16) & 0xff;
 	int invert = (kcontrol->private_value >> 24) & 0xff;
+	long *value = ucontrol->value.integer.value;
 
 	spin_lock_irq(&chip->reg_lock);
-	ucontrol->value.integer.value[0] = (inw(chip->port + reg) >> shift_left) & mask;
-	ucontrol->value.integer.value[1] = (inw(chip->port + reg) >> shift_right) & mask;
+	value[0] = (fm801_ioread16(chip, reg) >> shift_left) & mask;
+	value[1] = (fm801_ioread16(chip, reg) >> shift_right) & mask;
 	spin_unlock_irq(&chip->reg_lock);
 	if (invert) {
-		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
-		ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
+		value[0] = mask - value[0];
+		value[1] = mask - value[1];
 	}
 	return 0;
 }
@@ -1080,26 +1098,20 @@
 	return -EIO;
 }
 
-static int snd_fm801_chip_init(struct fm801 *chip, int resume)
+static int reset_codec(struct fm801 *chip)
 {
-	unsigned short cmdw;
-
-	if (chip->tea575x_tuner & TUNER_ONLY)
-		goto __ac97_ok;
-
 	/* codec cold reset + AC'97 warm reset */
 	fm801_writew(chip, CODEC_CTRL, (1 << 5) | (1 << 6));
 	fm801_readw(chip, CODEC_CTRL); /* flush posting data */
 	udelay(100);
 	fm801_writew(chip, CODEC_CTRL, 0);
 
-	if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0)
-		if (!resume) {
-			dev_info(chip->card->dev,
-				 "Primary AC'97 codec not found, assume SF64-PCR (tuner-only)\n");
-			chip->tea575x_tuner = 3 | TUNER_ONLY;
-			goto __ac97_ok;
-		}
+	return wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750));
+}
+
+static void snd_fm801_chip_multichannel_init(struct fm801 *chip)
+{
+	unsigned short cmdw;
 
 	if (chip->multichannel) {
 		if (chip->secondary_addr) {
@@ -1126,8 +1138,11 @@
 		/* cause timeout problems */
 		wait_for_codec(chip, 0, AC97_VENDOR_ID1, msecs_to_jiffies(750));
 	}
+}
 
-      __ac97_ok:
+static void snd_fm801_chip_init(struct fm801 *chip)
+{
+	unsigned short cmdw;
 
 	/* init volume */
 	fm801_writew(chip, PCM_VOL, 0x0808);
@@ -1148,11 +1163,8 @@
 	/* interrupt clear */
 	fm801_writew(chip, IRQ_STATUS,
 		     FM801_IRQ_PLAYBACK | FM801_IRQ_CAPTURE | FM801_IRQ_MPU);
-
-	return 0;
 }
 
-
 static int snd_fm801_free(struct fm801 *chip)
 {
 	unsigned short cmdw;
@@ -1165,6 +1177,8 @@
 	cmdw |= 0x00c3;
 	fm801_writew(chip, IRQ_MASK, cmdw);
 
+	devm_free_irq(chip->dev, chip->irq, chip);
+
       __end_hw:
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
 	if (!(chip->tea575x_tuner & TUNER_DISABLED)) {
@@ -1201,13 +1215,29 @@
 		return -ENOMEM;
 	spin_lock_init(&chip->reg_lock);
 	chip->card = card;
-	chip->pci = pci;
+	chip->dev = &pci->dev;
 	chip->irq = -1;
 	chip->tea575x_tuner = tea575x_tuner;
 	if ((err = pci_request_regions(pci, "FM801")) < 0)
 		return err;
 	chip->port = pci_resource_start(pci, 0);
-	if ((tea575x_tuner & TUNER_ONLY) == 0) {
+
+	if (pci->revision >= 0xb1)	/* FM801-AU */
+		chip->multichannel = 1;
+
+	if (!(chip->tea575x_tuner & TUNER_ONLY)) {
+		if (reset_codec(chip) < 0) {
+			dev_info(chip->card->dev,
+				 "Primary AC'97 codec not found, assume SF64-PCR (tuner-only)\n");
+			chip->tea575x_tuner = 3 | TUNER_ONLY;
+		} else {
+			snd_fm801_chip_multichannel_init(chip);
+		}
+	}
+
+	snd_fm801_chip_init(chip);
+
+	if ((chip->tea575x_tuner & TUNER_ONLY) == 0) {
 		if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
 				IRQF_SHARED, KBUILD_MODNAME, chip)) {
 			dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
@@ -1218,13 +1248,6 @@
 		pci_set_master(pci);
 	}
 
-	if (pci->revision >= 0xb1)	/* FM801-AU */
-		chip->multichannel = 1;
-
-	snd_fm801_chip_init(chip, 0);
-	/* init might set tuner access method */
-	tea575x_tuner = chip->tea575x_tuner;
-
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
 		snd_fm801_free(chip);
 		return err;
@@ -1241,14 +1264,16 @@
 	chip->tea.private_data = chip;
 	chip->tea.ops = &snd_fm801_tea_ops;
 	sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
-	if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
-	    (tea575x_tuner & TUNER_TYPE_MASK) < 4) {
+	if ((chip->tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
+	    (chip->tea575x_tuner & TUNER_TYPE_MASK) < 4) {
 		if (snd_tea575x_init(&chip->tea, THIS_MODULE)) {
 			dev_err(card->dev, "TEA575x radio not found\n");
 			snd_fm801_free(chip);
 			return -ENODEV;
 		}
-	} else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) {
+	} else if ((chip->tea575x_tuner & TUNER_TYPE_MASK) == 0) {
+		unsigned int tuner_only = chip->tea575x_tuner & TUNER_ONLY;
+
 		/* autodetect tuner connection */
 		for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) {
 			chip->tea575x_tuner = tea575x_tuner;
@@ -1263,6 +1288,8 @@
 			dev_err(card->dev, "TEA575x radio not found\n");
 			chip->tea575x_tuner = TUNER_DISABLED;
 		}
+
+		chip->tea575x_tuner |= tuner_only;
 	}
 	if (!(chip->tea575x_tuner & TUNER_DISABLED)) {
 		strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name,
@@ -1366,12 +1393,18 @@
 	int i;
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-	snd_pcm_suspend_all(chip->pcm);
-	snd_ac97_suspend(chip->ac97);
-	snd_ac97_suspend(chip->ac97_sec);
+
 	for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
-		chip->saved_regs[i] = inw(chip->port + saved_regs[i]);
-	/* FIXME: tea575x suspend */
+		chip->saved_regs[i] = fm801_ioread16(chip, saved_regs[i]);
+
+	if (chip->tea575x_tuner & TUNER_ONLY) {
+		/* FIXME: tea575x suspend */
+	} else {
+		snd_pcm_suspend_all(chip->pcm);
+		snd_ac97_suspend(chip->ac97);
+		snd_ac97_suspend(chip->ac97_sec);
+	}
+
 	return 0;
 }
 
@@ -1381,11 +1414,23 @@
 	struct fm801 *chip = card->private_data;
 	int i;
 
-	snd_fm801_chip_init(chip, 1);
-	snd_ac97_resume(chip->ac97);
-	snd_ac97_resume(chip->ac97_sec);
+	if (chip->tea575x_tuner & TUNER_ONLY) {
+		snd_fm801_chip_init(chip);
+	} else {
+		reset_codec(chip);
+		snd_fm801_chip_multichannel_init(chip);
+		snd_fm801_chip_init(chip);
+		snd_ac97_resume(chip->ac97);
+		snd_ac97_resume(chip->ac97_sec);
+	}
+
 	for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
-		outw(chip->saved_regs[i], chip->port + saved_regs[i]);
+		fm801_iowrite16(chip, saved_regs[i], chip->saved_regs[i]);
+
+#ifdef CONFIG_SND_FM801_TEA575X_BOOL
+	if (!(chip->tea575x_tuner & TUNER_DISABLED))
+		snd_tea575x_set_freq(&chip->tea);
+#endif
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 	return 0;
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index 22dbfa5..37cf9ce 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -956,7 +956,7 @@
 	status = azx_readb(chip, RIRBSTS);
 	if (status & RIRB_INT_MASK) {
 		if (status & RIRB_INT_RESPONSE) {
-			if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY)
+			if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
 				udelay(80);
 			snd_hdac_bus_update_rirb(bus);
 		}
@@ -1050,16 +1050,10 @@
 	if (chip->get_position[0] != azx_get_pos_lpib ||
 	    chip->get_position[1] != azx_get_pos_lpib)
 		bus->core.use_posbuf = true;
-	if (chip->bdl_pos_adj)
-		bus->core.bdl_pos_adj = chip->bdl_pos_adj[chip->dev_index];
+	bus->core.bdl_pos_adj = chip->bdl_pos_adj;
 	if (chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR)
 		bus->core.corbrp_self_clear = true;
 
-	if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
-		dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
-		bus->needs_damn_long_delay = 1;
-	}
-
 	if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY)
 		bus->core.align_bdle_4k = true;
 
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h
index 7b635d6..ec63bbf 100644
--- a/sound/pci/hda/hda_controller.h
+++ b/sound/pci/hda/hda_controller.h
@@ -32,21 +32,25 @@
 #define AZX_DCAPS_NO_MSI	(1 << 9)	/* No MSI support */
 #define AZX_DCAPS_SNOOP_MASK	(3 << 10)	/* snoop type mask */
 #define AZX_DCAPS_SNOOP_OFF	(1 << 12)	/* snoop default off */
-#define AZX_DCAPS_RIRB_DELAY	(1 << 13)	/* Long delay in read loop */
-#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14)	/* Put a delay before read */
+/* 13 unused */
+/* 14 unused */
 #define AZX_DCAPS_CTX_WORKAROUND (1 << 15)	/* X-Fi workaround */
 #define AZX_DCAPS_POSFIX_LPIB	(1 << 16)	/* Use LPIB as default */
-#define AZX_DCAPS_POSFIX_VIA	(1 << 17)	/* Use VIACOMBO as default */
+/* 17 unused */
 #define AZX_DCAPS_NO_64BIT	(1 << 18)	/* No 64bit address */
 #define AZX_DCAPS_SYNC_WRITE	(1 << 19)	/* sync each cmd write */
 #define AZX_DCAPS_OLD_SSYNC	(1 << 20)	/* Old SSYNC reg for ICH */
 #define AZX_DCAPS_NO_ALIGN_BUFSIZE (1 << 21)	/* no buffer size alignment */
 /* 22 unused */
 #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23)	/* BDLE in 4k boundary */
-#define AZX_DCAPS_REVERSE_ASSIGN (1 << 24)	/* Assign devices in reverse order */
+/* 24 unused */
 #define AZX_DCAPS_COUNT_LPIB_DELAY  (1 << 25)	/* Take LPIB as delay */
 #define AZX_DCAPS_PM_RUNTIME	(1 << 26)	/* runtime PM support */
+#ifdef CONFIG_SND_HDA_I915
 #define AZX_DCAPS_I915_POWERWELL (1 << 27)	/* HSW i915 powerwell support */
+#else
+#define AZX_DCAPS_I915_POWERWELL 0		/* NOP */
+#endif
 #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28)	/* CORBRP clears itself after reset */
 #define AZX_DCAPS_NO_MSI64      (1 << 29)	/* Stick to 32-bit MSIs */
 #define AZX_DCAPS_SEPARATE_STREAM_TAG	(1 << 30) /* capture and playback use separate stream tag */
@@ -143,7 +147,7 @@
 #endif
 
 	/* flags */
-	const int *bdl_pos_adj;
+	int bdl_pos_adj;
 	int poll_count;
 	unsigned int running:1;
 	unsigned int single_cmd:1;
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index 563984d..bc2e082 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -253,6 +253,7 @@
 	int mnl;
 	int i;
 
+	memset(e, 0, sizeof(*e));
 	e->eld_ver = GRAB_BITS(buf, 0, 3, 5);
 	if (e->eld_ver != ELD_VER_CEA_861D &&
 	    e->eld_ver != ELD_VER_PARTIAL) {
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index c6e8a65..30c8efe 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -279,22 +279,6 @@
 }
 
 /**
- * snd_hda_get_nid_path - get the path between the given NIDs
- * @codec: the HDA codec
- * @from_nid: the NID where the path start from
- * @to_nid: the NID where the path ends at
- *
- * Return the found nid_path object or NULL for error.
- * Passing 0 to either @from_nid or @to_nid behaves as a wildcard.
- */
-struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
-				      hda_nid_t from_nid, hda_nid_t to_nid)
-{
-	return get_nid_path(codec, from_nid, to_nid, 0);
-}
-EXPORT_SYMBOL_GPL(snd_hda_get_nid_path);
-
-/**
  * snd_hda_get_path_idx - get the index number corresponding to the path
  * instance
  * @codec: the HDA codec
@@ -451,7 +435,7 @@
 	return true;
 }
 
-/**
+/*
  * snd_hda_parse_nid_path - parse the widget path from the given nid to
  * the target nid
  * @codec: the HDA codec
@@ -470,7 +454,7 @@
  * with the negative of given value are excluded, only other paths are chosen.
  * when @anchor_nid is zero, no special handling about path selection.
  */
-bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
+static bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
 			    hda_nid_t to_nid, int anchor_nid,
 			    struct nid_path *path)
 {
@@ -481,7 +465,6 @@
 	}
 	return false;
 }
-EXPORT_SYMBOL_GPL(snd_hda_parse_nid_path);
 
 /**
  * snd_hda_add_new_path - parse the path between the given NIDs and
@@ -771,9 +754,6 @@
 	unsigned int caps;
 	unsigned int mask, val;
 
-	if (!enable && is_active_nid(codec, nid, dir, idx_to_check))
-		return;
-
 	caps = query_amp_caps(codec, nid, dir);
 	val = get_amp_val_to_activate(codec, nid, dir, caps, enable);
 	mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps);
@@ -784,12 +764,22 @@
 	update_amp(codec, nid, dir, idx, mask, val);
 }
 
+static void check_and_activate_amp(struct hda_codec *codec, hda_nid_t nid,
+				   int dir, int idx, int idx_to_check,
+				   bool enable)
+{
+	/* check whether the given amp is still used by others */
+	if (!enable && is_active_nid(codec, nid, dir, idx_to_check))
+		return;
+	activate_amp(codec, nid, dir, idx, idx_to_check, enable);
+}
+
 static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
 			     int i, bool enable)
 {
 	hda_nid_t nid = path->path[i];
 	init_amp(codec, nid, HDA_OUTPUT, 0);
-	activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable);
+	check_and_activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable);
 }
 
 static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
@@ -817,9 +807,16 @@
 	 * when aa-mixer is available, we need to enable the path as well
 	 */
 	for (n = 0; n < nums; n++) {
-		if (n != idx && (!add_aamix || conn[n] != spec->mixer_merge_nid))
-			continue;
-		activate_amp(codec, nid, HDA_INPUT, n, idx, enable);
+		if (n != idx) {
+			if (conn[n] != spec->mixer_merge_nid)
+				continue;
+			/* when aamix is disabled, force to off */
+			if (!add_aamix) {
+				activate_amp(codec, nid, HDA_INPUT, n, n, false);
+				continue;
+			}
+		}
+		check_and_activate_amp(codec, nid, HDA_INPUT, n, idx, enable);
 	}
 }
 
@@ -1580,6 +1577,12 @@
 	return found;
 }
 
+static inline bool has_aamix_out_paths(struct hda_gen_spec *spec)
+{
+	return spec->aamix_out_paths[0] || spec->aamix_out_paths[1] ||
+		spec->aamix_out_paths[2];
+}
+
 /* create a new path including aamix if available, and return its index */
 static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
 {
@@ -2422,25 +2425,51 @@
 	}
 }
 
+/* re-initialize the output paths; only called from loopback_mixing_put() */
+static void update_output_paths(struct hda_codec *codec, int num_outs,
+				const int *paths)
+{
+	struct hda_gen_spec *spec = codec->spec;
+	struct nid_path *path;
+	int i;
+
+	for (i = 0; i < num_outs; i++) {
+		path = snd_hda_get_path_from_idx(codec, paths[i]);
+		if (path)
+			snd_hda_activate_path(codec, path, path->active,
+					      spec->aamix_mode);
+	}
+}
+
 static int loopback_mixing_put(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct hda_gen_spec *spec = codec->spec;
+	const struct auto_pin_cfg *cfg = &spec->autocfg;
 	unsigned int val = ucontrol->value.enumerated.item[0];
 
 	if (val == spec->aamix_mode)
 		return 0;
 	spec->aamix_mode = val;
-	update_aamix_paths(codec, val, spec->out_paths[0],
-			   spec->aamix_out_paths[0],
-			   spec->autocfg.line_out_type);
-	update_aamix_paths(codec, val, spec->hp_paths[0],
-			   spec->aamix_out_paths[1],
-			   AUTO_PIN_HP_OUT);
-	update_aamix_paths(codec, val, spec->speaker_paths[0],
-			   spec->aamix_out_paths[2],
-			   AUTO_PIN_SPEAKER_OUT);
+	if (has_aamix_out_paths(spec)) {
+		update_aamix_paths(codec, val, spec->out_paths[0],
+				   spec->aamix_out_paths[0],
+				   cfg->line_out_type);
+		update_aamix_paths(codec, val, spec->hp_paths[0],
+				   spec->aamix_out_paths[1],
+				   AUTO_PIN_HP_OUT);
+		update_aamix_paths(codec, val, spec->speaker_paths[0],
+				   spec->aamix_out_paths[2],
+				   AUTO_PIN_SPEAKER_OUT);
+	} else {
+		update_output_paths(codec, cfg->line_outs, spec->out_paths);
+		if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+			update_output_paths(codec, cfg->hp_outs, spec->hp_paths);
+		if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+			update_output_paths(codec, cfg->speaker_outs,
+					    spec->speaker_paths);
+	}
 	return 1;
 }
 
@@ -2458,12 +2487,13 @@
 
 	if (!spec->mixer_nid)
 		return 0;
-	if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] ||
-	      spec->aamix_out_paths[2]))
-		return 0;
 	if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum))
 		return -ENOMEM;
 	spec->have_aamix_ctl = 1;
+	/* if no explicit aamix path is present (e.g. for Realtek codecs),
+	 * enable aamix as default -- just for compatibility
+	 */
+	spec->aamix_mode = !has_aamix_out_paths(spec);
 	return 0;
 }
 
@@ -5664,6 +5694,8 @@
 
 	if (!spec->have_aamix_ctl)
 		return;
+	if (!has_aamix_out_paths(spec))
+		return;
 	update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0],
 			   spec->aamix_out_paths[0],
 			   spec->autocfg.line_out_type);
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index 56e4139..f66fc7e 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -306,13 +306,8 @@
 int snd_hda_gen_init(struct hda_codec *codec);
 void snd_hda_gen_free(struct hda_codec *codec);
 
-struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
-				      hda_nid_t from_nid, hda_nid_t to_nid);
 int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path);
 struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx);
-bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
-			    hda_nid_t to_nid, int anchor_nid,
-			    struct nid_path *path);
 struct nid_path *
 snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
 		     hda_nid_t to_nid, int anchor_nid);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 3b36582..c0bef11 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -284,13 +284,19 @@
 	(AZX_DCAPS_OLD_SSYNC | AZX_DCAPS_NO_ALIGN_BUFSIZE)
 
 /* quirks for Intel PCH */
-#define AZX_DCAPS_INTEL_PCH_NOPM \
+#define AZX_DCAPS_INTEL_PCH_BASE \
 	(AZX_DCAPS_NO_ALIGN_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\
-	 AZX_DCAPS_REVERSE_ASSIGN | AZX_DCAPS_SNOOP_TYPE(SCH))
+	 AZX_DCAPS_SNOOP_TYPE(SCH))
 
+/* PCH up to IVB; no runtime PM */
+#define AZX_DCAPS_INTEL_PCH_NOPM \
+	(AZX_DCAPS_INTEL_PCH_BASE)
+
+/* PCH for HSW/BDW; with runtime PM */
 #define AZX_DCAPS_INTEL_PCH \
-	(AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_PM_RUNTIME)
+	(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME)
 
+/* HSW HDMI */
 #define AZX_DCAPS_INTEL_HASWELL \
 	(/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\
 	 AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\
@@ -332,7 +338,7 @@
 
 /* quirks for Nvidia */
 #define AZX_DCAPS_PRESET_NVIDIA \
-	(AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI | /*AZX_DCAPS_ALIGN_BUFSIZE |*/ \
+	(AZX_DCAPS_NO_MSI | /*AZX_DCAPS_ALIGN_BUFSIZE |*/ \
 	 AZX_DCAPS_NO_64BIT | AZX_DCAPS_CORBRP_SELF_CLEAR |\
 	 AZX_DCAPS_SNOOP_TYPE(NVIDIA))
 
@@ -649,7 +655,7 @@
 	if (wallclk < (azx_dev->core.period_wallclk * 5) / 4 &&
 	    pos % azx_dev->core.period_bytes > azx_dev->core.period_bytes / 2)
 		/* NG - it's below the first next period boundary */
-		return chip->bdl_pos_adj[chip->dev_index] ? 0 : -1;
+		return chip->bdl_pos_adj ? 0 : -1;
 	azx_dev->core.start_wallclk += wallclk;
 	return 1; /* OK, it's fine */
 }
@@ -719,7 +725,7 @@
 
 	if (request_irq(chip->pci->irq, azx_interrupt,
 			chip->msi ? 0 : IRQF_SHARED,
-			KBUILD_MODNAME, chip)) {
+			chip->card->irq_descr, chip)) {
 		dev_err(chip->card->dev,
 			"unable to grab IRQ %d, disabling device\n",
 			chip->pci->irq);
@@ -1376,7 +1382,7 @@
 	}
 
 	/* Check VIA/ATI HD Audio Controller exist */
-	if (chip->driver_caps & AZX_DCAPS_POSFIX_VIA) {
+	if (chip->driver_type == AZX_DRIVER_VIA) {
 		dev_dbg(chip->card->dev, "Using VIACOMBO position fix\n");
 		return POS_FIX_VIACOMBO;
 	}
@@ -1539,6 +1545,26 @@
 	azx_probe_continue(&hda->chip);
 }
 
+static int default_bdl_pos_adj(struct azx *chip)
+{
+	/* some exceptions: Atoms seem problematic with value 1 */
+	if (chip->pci->vendor == PCI_VENDOR_ID_INTEL) {
+		switch (chip->pci->device) {
+		case 0x0f04: /* Baytrail */
+		case 0x2284: /* Braswell */
+			return 32;
+		}
+	}
+
+	switch (chip->driver_type) {
+	case AZX_DRIVER_ICH:
+	case AZX_DRIVER_PCH:
+		return 1;
+	default:
+		return 32;
+	}
+}
+
 /*
  * constructor
  */
@@ -1592,18 +1618,10 @@
 	chip->single_cmd = single_cmd;
 	azx_check_snoop_available(chip);
 
-	if (bdl_pos_adj[dev] < 0) {
-		switch (chip->driver_type) {
-		case AZX_DRIVER_ICH:
-		case AZX_DRIVER_PCH:
-			bdl_pos_adj[dev] = 1;
-			break;
-		default:
-			bdl_pos_adj[dev] = 32;
-			break;
-		}
-	}
-	chip->bdl_pos_adj = bdl_pos_adj;
+	if (bdl_pos_adj[dev] < 0)
+		chip->bdl_pos_adj = default_bdl_pos_adj(chip);
+	else
+		chip->bdl_pos_adj = bdl_pos_adj[dev];
 
 	err = azx_bus_init(chip, model[dev], &pci_hda_io_ops);
 	if (err < 0) {
@@ -1612,6 +1630,11 @@
 		return err;
 	}
 
+	if (chip->driver_type == AZX_DRIVER_NVIDIA) {
+		dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
+		chip->bus.needs_damn_long_delay = 1;
+	}
+
 	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
 	if (err < 0) {
 		dev_err(card->dev, "Error creating device [card]!\n");
@@ -2005,8 +2028,8 @@
 #endif /* CONFIG_SND_HDA_PATCH_LOADER */
 
 #ifndef CONFIG_SND_HDA_I915
-	if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
-		dev_err(card->dev, "Haswell must build in CONFIG_SND_HDA_I915\n");
+	if (CONTROLLER_IN_GPU(pci))
+		dev_err(card->dev, "Haswell/Broadwell HDMI/DP must build in CONFIG_SND_HDA_I915\n");
 #endif
 
 	if (schedule_probe)
@@ -2203,10 +2226,10 @@
 	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
 	/* Poulsbo */
 	{ PCI_DEVICE(0x8086, 0x811b),
-	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
+	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE },
 	/* Oaktrail */
 	{ PCI_DEVICE(0x8086, 0x080a),
-	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
+	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE },
 	/* BayTrail */
 	{ PCI_DEVICE(0x8086, 0x0f04),
 	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BAYTRAIL },
@@ -2318,8 +2341,7 @@
 	{ PCI_DEVICE(0x1002, 0xaae8),
 	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
 	/* VIA VT8251/VT8237A */
-	{ PCI_DEVICE(0x1106, 0x3288),
-	  .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA },
+	{ PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA },
 	/* VIA GFX VT7122/VX900 */
 	{ PCI_DEVICE(0x1106, 0x9170), .driver_data = AZX_DRIVER_GENERIC },
 	/* VIA GFX VT6122/VX11 */
@@ -2353,14 +2375,12 @@
 	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
 	  .class_mask = 0xffffff,
 	  .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
-	  AZX_DCAPS_NO_64BIT |
-	  AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
+	  AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB },
 #else
 	/* this entry seems still valid -- i.e. without emu20kx chip */
 	{ PCI_DEVICE(0x1102, 0x0009),
 	  .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
-	  AZX_DCAPS_NO_64BIT |
-	  AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
+	  AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB },
 #endif
 	/* CM8888 */
 	{ PCI_DEVICE(0x13f6, 0x5011),
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index 58c0aad..17fd817 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -464,6 +464,8 @@
 	if (err < 0)
 		return err;
 
+	chip->bus.needs_damn_long_delay = 1;
+
 	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
 	if (err < 0) {
 		dev_err(card->dev, "Error creating device\n");
@@ -481,8 +483,7 @@
 
 static int hda_tegra_probe(struct platform_device *pdev)
 {
-	const unsigned int driver_flags = AZX_DCAPS_RIRB_DELAY |
-					  AZX_DCAPS_CORBRP_SELF_CLEAR;
+	const unsigned int driver_flags = AZX_DCAPS_CORBRP_SELF_CLEAR;
 	struct snd_card *card;
 	struct azx *chip;
 	struct hda_tegra *hda;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index ef19890..6122b8c 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -901,6 +901,9 @@
 		snd_hda_pick_fixup(codec, cxt5051_fixup_models,
 				   cxt5051_fixups, cxt_fixups);
 		break;
+	case 0x14f150f2:
+		codec->power_save_node = 1;
+		/* Fall through */
 	default:
 		codec->pin_amp_workaround = 1;
 		snd_hda_pick_fixup(codec, cxt5066_fixup_models,
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 4b6fb66..426a29a 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -51,8 +51,10 @@
 #define is_broadwell(codec)    ((codec)->core.vendor_id == 0x80862808)
 #define is_skylake(codec) ((codec)->core.vendor_id == 0x80862809)
 #define is_broxton(codec) ((codec)->core.vendor_id == 0x8086280a)
+#define is_kabylake(codec) ((codec)->core.vendor_id == 0x8086280b)
 #define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec) \
-				|| is_skylake(codec) || is_broxton(codec))
+				|| is_skylake(codec) || is_broxton(codec) \
+				|| is_kabylake(codec))
 
 #define is_valleyview(codec) ((codec)->core.vendor_id == 0x80862882)
 #define is_cherryview(codec) ((codec)->core.vendor_id == 0x80862883)
@@ -83,6 +85,7 @@
 	struct mutex lock;
 	struct delayed_work work;
 	struct snd_kcontrol *eld_ctl;
+	struct snd_jack *acomp_jack; /* jack via audio component */
 	int repoll_count;
 	bool setup; /* the stream has been set up by prepare callback */
 	int channels; /* current number of channels */
@@ -150,8 +153,15 @@
 
 	/* i915/powerwell (Haswell+/Valleyview+) specific */
 	struct i915_audio_component_audio_ops i915_audio_ops;
+	bool i915_bound; /* was i915 bound in this driver? */
 };
 
+#ifdef CONFIG_SND_HDA_I915
+#define codec_has_acomp(codec) \
+	((codec)->bus->core.audio_component != NULL)
+#else
+#define codec_has_acomp(codec)	false
+#endif
 
 struct hdmi_audio_infoframe {
 	u8 type; /* 0x84 */
@@ -1530,7 +1540,59 @@
 	return 0;
 }
 
-static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
+/* update per_pin ELD from the given new ELD;
+ * setup info frame and notification accordingly
+ */
+static void update_eld(struct hda_codec *codec,
+		       struct hdmi_spec_per_pin *per_pin,
+		       struct hdmi_eld *eld)
+{
+	struct hdmi_eld *pin_eld = &per_pin->sink_eld;
+	bool old_eld_valid = pin_eld->eld_valid;
+	bool eld_changed;
+
+	if (eld->eld_valid)
+		snd_hdmi_show_eld(codec, &eld->info);
+
+	eld_changed = (pin_eld->eld_valid != eld->eld_valid);
+	if (eld->eld_valid && pin_eld->eld_valid)
+		if (pin_eld->eld_size != eld->eld_size ||
+		    memcmp(pin_eld->eld_buffer, eld->eld_buffer,
+			   eld->eld_size) != 0)
+			eld_changed = true;
+
+	pin_eld->eld_valid = eld->eld_valid;
+	pin_eld->eld_size = eld->eld_size;
+	if (eld->eld_valid)
+		memcpy(pin_eld->eld_buffer, eld->eld_buffer, eld->eld_size);
+	pin_eld->info = eld->info;
+
+	/*
+	 * Re-setup pin and infoframe. This is needed e.g. when
+	 * - sink is first plugged-in
+	 * - transcoder can change during stream playback on Haswell
+	 *   and this can make HW reset converter selection on a pin.
+	 */
+	if (eld->eld_valid && !old_eld_valid && per_pin->setup) {
+		if (is_haswell_plus(codec) || is_valleyview_plus(codec)) {
+			intel_verify_pin_cvt_connect(codec, per_pin);
+			intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
+						     per_pin->mux_idx);
+		}
+
+		hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
+	}
+
+	if (eld_changed)
+		snd_ctl_notify(codec->card,
+			       SNDRV_CTL_EVENT_MASK_VALUE |
+			       SNDRV_CTL_EVENT_MASK_INFO,
+			       &per_pin->eld_ctl->id);
+}
+
+/* update ELD and jack state via HD-audio verbs */
+static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
+					 int repoll)
 {
 	struct hda_jack_tbl *jack;
 	struct hda_codec *codec = per_pin->codec;
@@ -1547,9 +1609,8 @@
 	 * the unsolicited response to avoid custom WARs.
 	 */
 	int present;
-	bool update_eld = false;
-	bool eld_changed = false;
 	bool ret;
+	bool do_repoll = false;
 
 	snd_hda_power_up_pm(codec);
 	present = snd_hda_pin_sense(codec, pin_nid);
@@ -1570,66 +1631,19 @@
 						     &eld->eld_size) < 0)
 			eld->eld_valid = false;
 		else {
-			memset(&eld->info, 0, sizeof(struct parsed_hdmi_eld));
 			if (snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer,
 						    eld->eld_size) < 0)
 				eld->eld_valid = false;
 		}
-
-		if (eld->eld_valid) {
-			snd_hdmi_show_eld(codec, &eld->info);
-			update_eld = true;
-		}
-		else if (repoll) {
-			schedule_delayed_work(&per_pin->work,
-					      msecs_to_jiffies(300));
-			goto unlock;
-		}
+		if (!eld->eld_valid && repoll)
+			do_repoll = true;
 	}
 
-	if (pin_eld->eld_valid != eld->eld_valid)
-		eld_changed = true;
+	if (do_repoll)
+		schedule_delayed_work(&per_pin->work, msecs_to_jiffies(300));
+	else
+		update_eld(codec, per_pin, eld);
 
-	if (pin_eld->eld_valid && !eld->eld_valid)
-		update_eld = true;
-
-	if (update_eld) {
-		bool old_eld_valid = pin_eld->eld_valid;
-		pin_eld->eld_valid = eld->eld_valid;
-		if (pin_eld->eld_size != eld->eld_size ||
-			      memcmp(pin_eld->eld_buffer, eld->eld_buffer,
-				     eld->eld_size) != 0) {
-			memcpy(pin_eld->eld_buffer, eld->eld_buffer,
-			       eld->eld_size);
-			eld_changed = true;
-		}
-		pin_eld->eld_size = eld->eld_size;
-		pin_eld->info = eld->info;
-
-		/*
-		 * Re-setup pin and infoframe. This is needed e.g. when
-		 * - sink is first plugged-in (infoframe is not set up if !monitor_present)
-		 * - transcoder can change during stream playback on Haswell
-		 *   and this can make HW reset converter selection on a pin.
-		 */
-		if (eld->eld_valid && !old_eld_valid && per_pin->setup) {
-			if (is_haswell_plus(codec) ||
-				is_valleyview_plus(codec)) {
-				intel_verify_pin_cvt_connect(codec, per_pin);
-				intel_not_share_assigned_cvt(codec, pin_nid,
-							per_pin->mux_idx);
-			}
-
-			hdmi_setup_audio_infoframe(codec, per_pin,
-						   per_pin->non_pcm);
-		}
-	}
-
-	if (eld_changed)
-		snd_ctl_notify(codec->card,
-			       SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
-			       &per_pin->eld_ctl->id);
- unlock:
 	ret = !repoll || !pin_eld->monitor_present || pin_eld->eld_valid;
 
 	jack = snd_hda_jack_tbl_get(codec, pin_nid);
@@ -1641,6 +1655,54 @@
 	return ret;
 }
 
+/* update ELD and jack state via audio component */
+static void sync_eld_via_acomp(struct hda_codec *codec,
+			       struct hdmi_spec_per_pin *per_pin)
+{
+	struct hdmi_spec *spec = codec->spec;
+	struct hdmi_eld *eld = &spec->temp_eld;
+	int size;
+
+	mutex_lock(&per_pin->lock);
+	size = snd_hdac_acomp_get_eld(&codec->bus->core, per_pin->pin_nid,
+				      &eld->monitor_present, eld->eld_buffer,
+				      ELD_MAX_SIZE);
+	if (size < 0)
+		goto unlock;
+	if (size > 0) {
+		size = min(size, ELD_MAX_SIZE);
+		if (snd_hdmi_parse_eld(codec, &eld->info,
+				       eld->eld_buffer, size) < 0)
+			size = -EINVAL;
+	}
+
+	if (size > 0) {
+		eld->eld_valid = true;
+		eld->eld_size = size;
+	} else {
+		eld->eld_valid = false;
+		eld->eld_size = 0;
+	}
+
+	update_eld(codec, per_pin, eld);
+	snd_jack_report(per_pin->acomp_jack,
+			eld->monitor_present ? SND_JACK_AVOUT : 0);
+ unlock:
+	mutex_unlock(&per_pin->lock);
+}
+
+static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
+{
+	struct hda_codec *codec = per_pin->codec;
+
+	if (codec_has_acomp(codec)) {
+		sync_eld_via_acomp(codec, per_pin);
+		return false; /* don't call snd_hda_jack_report_sync() */
+	} else {
+		return hdmi_present_sense_via_verbs(per_pin, repoll);
+	}
+}
+
 static void hdmi_repoll_eld(struct work_struct *work)
 {
 	struct hdmi_spec_per_pin *per_pin =
@@ -1776,17 +1838,6 @@
 	return non_pcm;
 }
 
-/* There is a fixed mapping between audio pin node and display port
- * on current Intel platforms:
- * Pin Widget 5 - PORT B (port = 1 in i915 driver)
- * Pin Widget 6 - PORT C (port = 2 in i915 driver)
- * Pin Widget 7 - PORT D (port = 3 in i915 driver)
- */
-static int intel_pin2port(hda_nid_t pin_nid)
-{
-	return pin_nid - 4;
-}
-
 /*
  * HDMI callbacks
  */
@@ -1803,7 +1854,6 @@
 	struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 	hda_nid_t pin_nid = per_pin->pin_nid;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct i915_audio_component *acomp = codec->bus->core.audio_component;
 	bool non_pcm;
 	int pinctl;
 
@@ -1822,10 +1872,7 @@
 
 	/* Call sync_audio_rate to set the N/CTS/M manually if necessary */
 	/* Todo: add DP1.2 MST audio support later */
-	if (acomp && acomp->ops && acomp->ops->sync_audio_rate)
-		acomp->ops->sync_audio_rate(acomp->dev,
-				intel_pin2port(pin_nid),
-				runtime->rate);
+	snd_hdac_sync_audio_rate(&codec->bus->core, pin_nid, runtime->rate);
 
 	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
 	mutex_lock(&per_pin->lock);
@@ -2091,6 +2138,30 @@
 	return 0;
 }
 
+static void free_acomp_jack_priv(struct snd_jack *jack)
+{
+	struct hdmi_spec_per_pin *per_pin = jack->private_data;
+
+	per_pin->acomp_jack = NULL;
+}
+
+static int add_acomp_jack_kctl(struct hda_codec *codec,
+			       struct hdmi_spec_per_pin *per_pin,
+			       const char *name)
+{
+	struct snd_jack *jack;
+	int err;
+
+	err = snd_jack_new(codec->card, name, SND_JACK_AVOUT, &jack,
+			   true, false);
+	if (err < 0)
+		return err;
+	per_pin->acomp_jack = jack;
+	jack->private_data = per_pin;
+	jack->private_free = free_acomp_jack_priv;
+	return 0;
+}
+
 static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx)
 {
 	char hdmi_str[32] = "HDMI/DP";
@@ -2101,6 +2172,8 @@
 
 	if (pcmdev > 0)
 		sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
+	if (codec_has_acomp(codec))
+		return add_acomp_jack_kctl(codec, per_pin, hdmi_str);
 	phantom_jack = !is_jack_detectable(codec, per_pin->pin_nid);
 	if (phantom_jack)
 		strncat(hdmi_str, " Phantom",
@@ -2196,8 +2269,10 @@
 		hda_nid_t pin_nid = per_pin->pin_nid;
 
 		hdmi_init_pin(codec, pin_nid);
-		snd_hda_jack_detect_enable_callback(codec, pin_nid,
-			codec->jackpoll_interval > 0 ? jack_callback : NULL);
+		if (!codec_has_acomp(codec))
+			snd_hda_jack_detect_enable_callback(codec, pin_nid,
+				codec->jackpoll_interval > 0 ?
+				jack_callback : NULL);
 	}
 	return 0;
 }
@@ -2219,7 +2294,7 @@
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx;
 
-	if (is_haswell_plus(codec) || is_valleyview_plus(codec))
+	if (codec_has_acomp(codec))
 		snd_hdac_i915_register_notifier(NULL);
 
 	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
@@ -2227,8 +2302,12 @@
 
 		cancel_delayed_work_sync(&per_pin->work);
 		eld_proc_free(per_pin);
+		if (per_pin->acomp_jack)
+			snd_device_free(codec->card, per_pin->acomp_jack);
 	}
 
+	if (spec->i915_bound)
+		snd_hdac_i915_exit(&codec->bus->core);
 	hdmi_array_free(spec);
 	kfree(spec);
 }
@@ -2357,6 +2436,9 @@
 	 */
 	if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0)
 		return;
+	/* ditto during suspend/resume process itself */
+	if (atomic_read(&(codec)->core.in_pm))
+		return;
 
 	check_presence_and_report(codec, pin_nid);
 }
@@ -2373,6 +2455,12 @@
 	codec->spec = spec;
 	hdmi_array_init(spec, 4);
 
+	/* Try to bind with i915 for any Intel codecs (if not done yet) */
+	if (!codec_has_acomp(codec) &&
+	    (codec->core.vendor_id >> 16) == 0x8086)
+		if (!snd_hdac_i915_init(&codec->bus->core))
+			spec->i915_bound = true;
+
 	if (is_haswell_plus(codec)) {
 		intel_haswell_enable_all_pins(codec, true);
 		intel_haswell_fixup_enable_dp12(codec);
@@ -2388,7 +2476,7 @@
 			is_broxton(codec))
 		codec->core.link_power_control = 1;
 
-	if (is_haswell_plus(codec) || is_valleyview_plus(codec)) {
+	if (codec_has_acomp(codec)) {
 		codec->depop_delay = 0;
 		spec->i915_audio_ops.audio_ptr = codec;
 		spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify;
@@ -2396,6 +2484,8 @@
 	}
 
 	if (hdmi_parse_codec(codec) < 0) {
+		if (spec->i915_bound)
+			snd_hdac_i915_exit(&codec->bus->core);
 		codec->spec = NULL;
 		kfree(spec);
 		return -EINVAL;
@@ -3579,6 +3669,7 @@
 HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI",	patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI",	patch_generic_hdmi),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 3a89d82..8143c0e 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -4666,6 +4666,7 @@
 	ALC290_FIXUP_SUBWOOFER,
 	ALC290_FIXUP_SUBWOOFER_HSJACK,
 	ALC269_FIXUP_THINKPAD_ACPI,
+	ALC269_FIXUP_DMIC_THINKPAD_ACPI,
 	ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
 	ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
 	ALC255_FIXUP_HEADSET_MODE,
@@ -5103,6 +5104,12 @@
 		.type = HDA_FIXUP_FUNC,
 		.v.func = hda_fixup_thinkpad_acpi,
 	},
+	[ALC269_FIXUP_DMIC_THINKPAD_ACPI] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_inv_dmic,
+		.chained = true,
+		.chain_id = ALC269_FIXUP_THINKPAD_ACPI,
+	},
 	[ALC255_FIXUP_DELL1_MIC_NO_PRESENCE] = {
 		.type = HDA_FIXUP_PINS,
 		.v.pins = (const struct hda_pintbl[]) {
@@ -5324,6 +5331,7 @@
 	SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
 	SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS),
 	SND_PCI_QUIRK(0x1028, 0x05bd, "Dell Latitude E6440", ALC292_FIXUP_DELL_E7X),
+	SND_PCI_QUIRK(0x1028, 0x05be, "Dell Latitude E6540", ALC292_FIXUP_DELL_E7X),
 	SND_PCI_QUIRK(0x1028, 0x05ca, "Dell Latitude E7240", ALC292_FIXUP_DELL_E7X),
 	SND_PCI_QUIRK(0x1028, 0x05cb, "Dell Latitude E7440", ALC292_FIXUP_DELL_E7X),
 	SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER),
@@ -5332,6 +5340,7 @@
 	SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
 	SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
+	SND_PCI_QUIRK(0x1028, 0x062c, "Dell Latitude E5550", ALC292_FIXUP_DELL_E7X),
 	SND_PCI_QUIRK(0x1028, 0x062e, "Dell Latitude E7450", ALC292_FIXUP_DELL_E7X),
 	SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK),
 	SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
@@ -5457,6 +5466,7 @@
 	SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE),
 	SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
+	SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
 	SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
 	SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
 	SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -5617,6 +5627,10 @@
 		{0x21, 0x02211040}),
 	SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
 		{0x12, 0x90a60170},
+		{0x14, 0x90171130},
+		{0x21, 0x02211040}),
+	SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+		{0x12, 0x90a60170},
 		{0x14, 0x90170140},
 		{0x21, 0x02211050}),
 	SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell Inspiron 5548", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index 496dbd0..3bfdc78 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -174,7 +174,7 @@
 	return -ENOENT;
 }
 
-static struct snd_i2c_ops ap_cs8427_i2c_ops = {
+static const struct snd_i2c_ops ap_cs8427_i2c_ops = {
 	.sendbytes = ap_cs8427_sendbytes,
 	.readbytes = ap_cs8427_readbytes,
 	.probeaddr = ap_cs8427_probeaddr,
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 7ff7d88..7ea66ee 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -38,6 +38,7 @@
 
 # All the supported SoCs
 source "sound/soc/adi/Kconfig"
+source "sound/soc/amd/Kconfig"
 source "sound/soc/atmel/Kconfig"
 source "sound/soc/au1x/Kconfig"
 source "sound/soc/bcm/Kconfig"
@@ -50,6 +51,7 @@
 source "sound/soc/nuc900/Kconfig"
 source "sound/soc/omap/Kconfig"
 source "sound/soc/kirkwood/Kconfig"
+source "sound/soc/img/Kconfig"
 source "sound/soc/intel/Kconfig"
 source "sound/soc/mediatek/Kconfig"
 source "sound/soc/mxs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 8eb06db..9a30f21 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -18,6 +18,7 @@
 obj-$(CONFIG_SND_SOC)	+= codecs/
 obj-$(CONFIG_SND_SOC)	+= generic/
 obj-$(CONFIG_SND_SOC)	+= adi/
+obj-$(CONFIG_SND_SOC)	+= amd/
 obj-$(CONFIG_SND_SOC)	+= atmel/
 obj-$(CONFIG_SND_SOC)	+= au1x/
 obj-$(CONFIG_SND_SOC)	+= bcm/
@@ -27,6 +28,7 @@
 obj-$(CONFIG_SND_SOC)	+= dwc/
 obj-$(CONFIG_SND_SOC)	+= fsl/
 obj-$(CONFIG_SND_SOC)	+= jz4740/
+obj-$(CONFIG_SND_SOC)	+= img/
 obj-$(CONFIG_SND_SOC)	+= intel/
 obj-$(CONFIG_SND_SOC)	+= mediatek/
 obj-$(CONFIG_SND_SOC)	+= mxs/
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
new file mode 100644
index 0000000..78187eb
--- /dev/null
+++ b/sound/soc/amd/Kconfig
@@ -0,0 +1,4 @@
+config SND_SOC_AMD_ACP
+	tristate "AMD Audio Coprocessor support"
+	help
+	 This option enables ACP DMA support on AMD platform.
diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile
new file mode 100644
index 0000000..1a66ec0
--- /dev/null
+++ b/sound/soc/amd/Makefile
@@ -0,0 +1,3 @@
+snd-soc-acp-pcm-objs	:= acp-pcm-dma.o
+
+obj-$(CONFIG_SND_SOC_AMD_ACP) += snd-soc-acp-pcm.o
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
new file mode 100644
index 0000000..3191e0a
--- /dev/null
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -0,0 +1,1043 @@
+/*
+ * AMD ALSA SoC PCM Driver for ACP 2.x
+ *
+ * Copyright 2014-2015 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <linux/pm_runtime.h>
+
+#include <sound/soc.h>
+
+#include "acp.h"
+
+#define PLAYBACK_MIN_NUM_PERIODS    2
+#define PLAYBACK_MAX_NUM_PERIODS    2
+#define PLAYBACK_MAX_PERIOD_SIZE    16384
+#define PLAYBACK_MIN_PERIOD_SIZE    1024
+#define CAPTURE_MIN_NUM_PERIODS     2
+#define CAPTURE_MAX_NUM_PERIODS     2
+#define CAPTURE_MAX_PERIOD_SIZE     16384
+#define CAPTURE_MIN_PERIOD_SIZE     1024
+
+#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
+#define MIN_BUFFER MAX_BUFFER
+
+static const struct snd_pcm_hardware acp_pcm_hardware_playback = {
+	.info = SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH |
+		SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE |
+		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+	.channels_min = 1,
+	.channels_max = 8,
+	.rates = SNDRV_PCM_RATE_8000_96000,
+	.rate_min = 8000,
+	.rate_max = 96000,
+	.buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
+	.period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
+	.period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
+	.periods_min = PLAYBACK_MIN_NUM_PERIODS,
+	.periods_max = PLAYBACK_MAX_NUM_PERIODS,
+};
+
+static const struct snd_pcm_hardware acp_pcm_hardware_capture = {
+	.info = SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH |
+	    SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE |
+		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+	.channels_min = 1,
+	.channels_max = 2,
+	.rates = SNDRV_PCM_RATE_8000_48000,
+	.rate_min = 8000,
+	.rate_max = 48000,
+	.buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
+	.period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
+	.period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
+	.periods_min = CAPTURE_MIN_NUM_PERIODS,
+	.periods_max = CAPTURE_MAX_NUM_PERIODS,
+};
+
+struct audio_drv_data {
+	struct snd_pcm_substream *play_stream;
+	struct snd_pcm_substream *capture_stream;
+	void __iomem *acp_mmio;
+};
+
+static u32 acp_reg_read(void __iomem *acp_mmio, u32 reg)
+{
+	return readl(acp_mmio + (reg * 4));
+}
+
+static void acp_reg_write(u32 val, void __iomem *acp_mmio, u32 reg)
+{
+	writel(val, acp_mmio + (reg * 4));
+}
+
+/* Configure a given dma channel parameters - enable/disble,
+ * number of descriptors, priority
+ */
+static void config_acp_dma_channel(void __iomem *acp_mmio, u8 ch_num,
+				   u16 dscr_strt_idx, u16 num_dscrs,
+				   enum acp_dma_priority_level priority_level)
+{
+	u32 dma_ctrl;
+
+	/* disable the channel run field */
+	dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+	dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRun_MASK;
+	acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+
+	/* program a DMA channel with first descriptor to be processed. */
+	acp_reg_write((ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx_MASK
+			& dscr_strt_idx),
+			acp_mmio, mmACP_DMA_DSCR_STRT_IDX_0 + ch_num);
+
+	/* program a DMA channel with the number of descriptors to be
+	 * processed in the transfer
+	*/
+	acp_reg_write(ACP_DMA_DSCR_CNT_0__DMAChDscrCnt_MASK & num_dscrs,
+		acp_mmio, mmACP_DMA_DSCR_CNT_0 + ch_num);
+
+	/* set DMA channel priority */
+	acp_reg_write(priority_level, acp_mmio, mmACP_DMA_PRIO_0 + ch_num);
+}
+
+/* Initialize a dma descriptor in SRAM based on descritor information passed */
+static void config_dma_descriptor_in_sram(void __iomem *acp_mmio,
+					  u16 descr_idx,
+					  acp_dma_dscr_transfer_t *descr_info)
+{
+	u32 sram_offset;
+
+	sram_offset = (descr_idx * sizeof(acp_dma_dscr_transfer_t));
+
+	/* program the source base address. */
+	acp_reg_write(sram_offset, acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+	acp_reg_write(descr_info->src,	acp_mmio, mmACP_SRBM_Targ_Idx_Data);
+	/* program the destination base address. */
+	acp_reg_write(sram_offset + 4,	acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+	acp_reg_write(descr_info->dest, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
+
+	/* program the number of bytes to be transferred for this descriptor. */
+	acp_reg_write(sram_offset + 8,	acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+	acp_reg_write(descr_info->xfer_val, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
+}
+
+/* Initialize the DMA descriptor information for transfer between
+ * system memory <-> ACP SRAM
+ */
+static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
+					   u32 size, int direction,
+					   u32 pte_offset)
+{
+	u16 i;
+	u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
+	acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL];
+
+	for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) {
+		dmadscr[i].xfer_val = 0;
+		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+			dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12 + i;
+			dmadscr[i].dest = ACP_SHARED_RAM_BANK_1_ADDRESS +
+					(size / 2) - (i * (size/2));
+			dmadscr[i].src = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS
+				+ (pte_offset * SZ_4K) + (i * (size/2));
+			dmadscr[i].xfer_val |=
+			(ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM << 16) |
+			(size / 2);
+		} else {
+			dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14 + i;
+			dmadscr[i].src = ACP_SHARED_RAM_BANK_5_ADDRESS +
+					(i * (size/2));
+			dmadscr[i].dest = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS
+						+ (pte_offset * SZ_4K) +
+						(i * (size/2));
+			dmadscr[i].xfer_val |=
+			BIT(22) |
+			(ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION << 16) |
+			(size / 2);
+		}
+		config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
+						&dmadscr[i]);
+	}
+	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+		config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM,
+					PLAYBACK_START_DMA_DESCR_CH12,
+					NUM_DSCRS_PER_CHANNEL,
+					ACP_DMA_PRIORITY_LEVEL_NORMAL);
+	else
+		config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM,
+					CAPTURE_START_DMA_DESCR_CH14,
+					NUM_DSCRS_PER_CHANNEL,
+					ACP_DMA_PRIORITY_LEVEL_NORMAL);
+}
+
+/* Initialize the DMA descriptor information for transfer between
+ * ACP SRAM <-> I2S
+ */
+static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio,
+					   u32 size, int direction)
+{
+
+	u16 i;
+	u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13;
+	acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL];
+
+	for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) {
+		dmadscr[i].xfer_val = 0;
+		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+			dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13 + i;
+			dmadscr[i].src = ACP_SHARED_RAM_BANK_1_ADDRESS +
+					 (i * (size/2));
+			/* dmadscr[i].dest is unused by hardware. */
+			dmadscr[i].dest = 0;
+			dmadscr[i].xfer_val |= BIT(22) | (TO_ACP_I2S_1 << 16) |
+						(size / 2);
+		} else {
+			dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15 + i;
+			/* dmadscr[i].src is unused by hardware. */
+			dmadscr[i].src = 0;
+			dmadscr[i].dest = ACP_SHARED_RAM_BANK_5_ADDRESS +
+					(i * (size / 2));
+			dmadscr[i].xfer_val |= BIT(22) |
+					(FROM_ACP_I2S_1 << 16) | (size / 2);
+		}
+		config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
+						&dmadscr[i]);
+	}
+	/* Configure the DMA channel with the above descriptore */
+	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+		config_acp_dma_channel(acp_mmio, ACP_TO_I2S_DMA_CH_NUM,
+					PLAYBACK_START_DMA_DESCR_CH13,
+					NUM_DSCRS_PER_CHANNEL,
+					ACP_DMA_PRIORITY_LEVEL_NORMAL);
+	else
+		config_acp_dma_channel(acp_mmio, I2S_TO_ACP_DMA_CH_NUM,
+					CAPTURE_START_DMA_DESCR_CH15,
+					NUM_DSCRS_PER_CHANNEL,
+					ACP_DMA_PRIORITY_LEVEL_NORMAL);
+}
+
+/* Create page table entries in ACP SRAM for the allocated memory */
+static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
+			   u16 num_of_pages, u32 pte_offset)
+{
+	u16 page_idx;
+	u64 addr;
+	u32 low;
+	u32 high;
+	u32 offset;
+
+	offset	= ACP_DAGB_GRP_SRBM_SRAM_BASE_OFFSET + (pte_offset * 8);
+	for (page_idx = 0; page_idx < (num_of_pages); page_idx++) {
+		/* Load the low address of page int ACP SRAM through SRBM */
+		acp_reg_write((offset + (page_idx * 8)),
+			acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+		addr = page_to_phys(pg);
+
+		low = lower_32_bits(addr);
+		high = upper_32_bits(addr);
+
+		acp_reg_write(low, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
+
+		/* Load the High address of page int ACP SRAM through SRBM */
+		acp_reg_write((offset + (page_idx * 8) + 4),
+			acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
+
+		/* page enable in ACP */
+		high |= BIT(31);
+		acp_reg_write(high, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
+
+		/* Move to next physically contiguos page */
+		pg++;
+	}
+}
+
+static void config_acp_dma(void __iomem *acp_mmio,
+			   struct audio_substream_data *audio_config)
+{
+	u32 pte_offset;
+
+	if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK)
+		pte_offset = ACP_PLAYBACK_PTE_OFFSET;
+	else
+		pte_offset = ACP_CAPTURE_PTE_OFFSET;
+
+	acp_pte_config(acp_mmio, audio_config->pg, audio_config->num_of_pages,
+			pte_offset);
+
+	/* Configure System memory <-> ACP SRAM DMA descriptors */
+	set_acp_sysmem_dma_descriptors(acp_mmio, audio_config->size,
+				       audio_config->direction, pte_offset);
+
+	/* Configure ACP SRAM <-> I2S DMA descriptors */
+	set_acp_to_i2s_dma_descriptors(acp_mmio, audio_config->size,
+					audio_config->direction);
+}
+
+/* Start a given DMA channel transfer */
+static void acp_dma_start(void __iomem *acp_mmio,
+			 u16 ch_num, bool is_circular)
+{
+	u32 dma_ctrl;
+
+	/* read the dma control register and disable the channel run field */
+	dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+
+	/* Invalidating the DAGB cache */
+	acp_reg_write(1, acp_mmio, mmACP_DAGB_ATU_CTRL);
+
+	/* configure the DMA channel and start the DMA transfer
+	 * set dmachrun bit to start the transfer and enable the
+	 * interrupt on completion of the dma transfer
+	 */
+	dma_ctrl |= ACP_DMA_CNTL_0__DMAChRun_MASK;
+
+	switch (ch_num) {
+	case ACP_TO_I2S_DMA_CH_NUM:
+	case ACP_TO_SYSRAM_CH_NUM:
+	case I2S_TO_ACP_DMA_CH_NUM:
+		dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
+		break;
+	default:
+		dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
+		break;
+	}
+
+	/* enable  for ACP SRAM to/from I2S DMA channel */
+	if (is_circular == true)
+		dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
+	else
+		dma_ctrl &= ~ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
+
+	acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+}
+
+/* Stop a given DMA channel transfer */
+static int acp_dma_stop(void __iomem *acp_mmio, u8 ch_num)
+{
+	u32 dma_ctrl;
+	u32 dma_ch_sts;
+	u32 count = ACP_DMA_RESET_TIME;
+
+	dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+
+	/* clear the dma control register fields before writing zero
+	 * in reset bit
+	*/
+	dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRun_MASK;
+	dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
+
+	acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+	dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS);
+
+	if (dma_ch_sts & BIT(ch_num)) {
+		/* set the reset bit for this channel to stop the dma
+		*  transfer
+		*/
+		dma_ctrl |= ACP_DMA_CNTL_0__DMAChRst_MASK;
+		acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
+	}
+
+	/* check the channel status bit for some time and return the status */
+	while (true) {
+		dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS);
+		if (!(dma_ch_sts & BIT(ch_num))) {
+			/* clear the reset flag after successfully stopping
+			* the dma transfer and break from the loop
+			*/
+			dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRst_MASK;
+
+			acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0
+								+ ch_num);
+			break;
+		}
+		if (--count == 0) {
+			pr_err("Failed to stop ACP DMA channel : %d\n", ch_num);
+			return -ETIMEDOUT;
+		}
+		udelay(100);
+	}
+	return 0;
+}
+
+static void acp_set_sram_bank_state(void __iomem *acp_mmio, u16 bank,
+					bool power_on)
+{
+	u32 val, req_reg, sts_reg, sts_reg_mask;
+	u32 loops = 1000;
+
+	if (bank < 32) {
+		req_reg = mmACP_MEM_SHUT_DOWN_REQ_LO;
+		sts_reg = mmACP_MEM_SHUT_DOWN_STS_LO;
+		sts_reg_mask = 0xFFFFFFFF;
+
+	} else {
+		bank -= 32;
+		req_reg = mmACP_MEM_SHUT_DOWN_REQ_HI;
+		sts_reg = mmACP_MEM_SHUT_DOWN_STS_HI;
+		sts_reg_mask = 0x0000FFFF;
+	}
+
+	val = acp_reg_read(acp_mmio, req_reg);
+	if (val & (1 << bank)) {
+		/* bank is in off state */
+		if (power_on == true)
+			/* request to on */
+			val &= ~(1 << bank);
+		else
+			/* request to off */
+			return;
+	} else {
+		/* bank is in on state */
+		if (power_on == false)
+			/* request to off */
+			val |= 1 << bank;
+		else
+			/* request to on */
+			return;
+	}
+	acp_reg_write(val, acp_mmio, req_reg);
+
+	while (acp_reg_read(acp_mmio, sts_reg) != sts_reg_mask) {
+		if (!loops--) {
+			pr_err("ACP SRAM bank %d state change failed\n", bank);
+			break;
+		}
+		cpu_relax();
+	}
+}
+
+/* Initialize and bring ACP hardware to default state. */
+static int acp_init(void __iomem *acp_mmio)
+{
+	u16 bank;
+	u32 val, count, sram_pte_offset;
+
+	/* Assert Soft reset of ACP */
+	val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET);
+
+	val |= ACP_SOFT_RESET__SoftResetAud_MASK;
+	acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET);
+
+	count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE;
+	while (true) {
+		val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET);
+		if (ACP_SOFT_RESET__SoftResetAudDone_MASK ==
+		    (val & ACP_SOFT_RESET__SoftResetAudDone_MASK))
+			break;
+		if (--count == 0) {
+			pr_err("Failed to reset ACP\n");
+			return -ETIMEDOUT;
+		}
+		udelay(100);
+	}
+
+	/* Enable clock to ACP and wait until the clock is enabled */
+	val = acp_reg_read(acp_mmio, mmACP_CONTROL);
+	val = val | ACP_CONTROL__ClkEn_MASK;
+	acp_reg_write(val, acp_mmio, mmACP_CONTROL);
+
+	count = ACP_CLOCK_EN_TIME_OUT_VALUE;
+
+	while (true) {
+		val = acp_reg_read(acp_mmio, mmACP_STATUS);
+		if (val & (u32) 0x1)
+			break;
+		if (--count == 0) {
+			pr_err("Failed to reset ACP\n");
+			return -ETIMEDOUT;
+		}
+		udelay(100);
+	}
+
+	/* Deassert the SOFT RESET flags */
+	val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET);
+	val &= ~ACP_SOFT_RESET__SoftResetAud_MASK;
+	acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET);
+
+	/* initiailize Onion control DAGB register */
+	acp_reg_write(ACP_ONION_CNTL_DEFAULT, acp_mmio,
+			mmACP_AXI2DAGB_ONION_CNTL);
+
+	/* initiailize Garlic control DAGB registers */
+	acp_reg_write(ACP_GARLIC_CNTL_DEFAULT, acp_mmio,
+			mmACP_AXI2DAGB_GARLIC_CNTL);
+
+	sram_pte_offset = ACP_DAGB_GRP_SRAM_BASE_ADDRESS |
+			ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel_MASK |
+			ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel_MASK |
+			ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable_MASK;
+	acp_reg_write(sram_pte_offset,  acp_mmio, mmACP_DAGB_BASE_ADDR_GRP_1);
+	acp_reg_write(ACP_PAGE_SIZE_4K_ENABLE, acp_mmio,
+			mmACP_DAGB_PAGE_SIZE_GRP_1);
+
+	acp_reg_write(ACP_SRAM_BASE_ADDRESS, acp_mmio,
+			mmACP_DMA_DESC_BASE_ADDR);
+
+	/* Num of descriptiors in SRAM 0x4, means 256 descriptors;(64 * 4) */
+	acp_reg_write(0x4, acp_mmio, mmACP_DMA_DESC_MAX_NUM_DSCR);
+	acp_reg_write(ACP_EXTERNAL_INTR_CNTL__DMAIOCMask_MASK,
+		acp_mmio, mmACP_EXTERNAL_INTR_CNTL);
+
+       /* When ACP_TILE_P1 is turned on, all SRAM banks get turned on.
+	* Now, turn off all of them. This can't be done in 'poweron' of
+	* ACP pm domain, as this requires ACP to be initialized.
+	*/
+	for (bank = 1; bank < 48; bank++)
+		acp_set_sram_bank_state(acp_mmio, bank, false);
+
+	return 0;
+}
+
+/* Deintialize ACP */
+static int acp_deinit(void __iomem *acp_mmio)
+{
+	u32 val;
+	u32 count;
+
+	/* Assert Soft reset of ACP */
+	val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET);
+
+	val |= ACP_SOFT_RESET__SoftResetAud_MASK;
+	acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET);
+
+	count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE;
+	while (true) {
+		val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET);
+		if (ACP_SOFT_RESET__SoftResetAudDone_MASK ==
+		    (val & ACP_SOFT_RESET__SoftResetAudDone_MASK))
+			break;
+		if (--count == 0) {
+			pr_err("Failed to reset ACP\n");
+			return -ETIMEDOUT;
+		}
+		udelay(100);
+	}
+	/** Disable ACP clock */
+	val = acp_reg_read(acp_mmio, mmACP_CONTROL);
+	val &= ~ACP_CONTROL__ClkEn_MASK;
+	acp_reg_write(val, acp_mmio, mmACP_CONTROL);
+
+	count = ACP_CLOCK_EN_TIME_OUT_VALUE;
+
+	while (true) {
+		val = acp_reg_read(acp_mmio, mmACP_STATUS);
+		if (!(val & (u32) 0x1))
+			break;
+		if (--count == 0) {
+			pr_err("Failed to reset ACP\n");
+			return -ETIMEDOUT;
+		}
+		udelay(100);
+	}
+	return 0;
+}
+
+/* ACP DMA irq handler routine for playback, capture usecases */
+static irqreturn_t dma_irq_handler(int irq, void *arg)
+{
+	u16 dscr_idx;
+	u32 intr_flag, ext_intr_status;
+	struct audio_drv_data *irq_data;
+	void __iomem *acp_mmio;
+	struct device *dev = arg;
+	bool valid_irq = false;
+
+	irq_data = dev_get_drvdata(dev);
+	acp_mmio = irq_data->acp_mmio;
+
+	ext_intr_status = acp_reg_read(acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+	intr_flag = (((ext_intr_status &
+		      ACP_EXTERNAL_INTR_STAT__DMAIOCStat_MASK) >>
+		     ACP_EXTERNAL_INTR_STAT__DMAIOCStat__SHIFT));
+
+	if ((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) != 0) {
+		valid_irq = true;
+		if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_13) ==
+				PLAYBACK_START_DMA_DESCR_CH13)
+			dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
+		else
+			dscr_idx = PLAYBACK_END_DMA_DESCR_CH12;
+		config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM, dscr_idx,
+				       1, 0);
+		acp_dma_start(acp_mmio, SYSRAM_TO_ACP_CH_NUM, false);
+
+		snd_pcm_period_elapsed(irq_data->play_stream);
+
+		acp_reg_write((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) << 16,
+				acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+	}
+
+	if ((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) != 0) {
+		valid_irq = true;
+		if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_15) ==
+				CAPTURE_START_DMA_DESCR_CH15)
+			dscr_idx = CAPTURE_END_DMA_DESCR_CH14;
+		else
+			dscr_idx = CAPTURE_START_DMA_DESCR_CH14;
+		config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM, dscr_idx,
+				       1, 0);
+		acp_dma_start(acp_mmio, ACP_TO_SYSRAM_CH_NUM, false);
+
+		acp_reg_write((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) << 16,
+				acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+	}
+
+	if ((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) != 0) {
+		valid_irq = true;
+		snd_pcm_period_elapsed(irq_data->capture_stream);
+		acp_reg_write((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) << 16,
+				acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+	}
+
+	if (valid_irq)
+		return IRQ_HANDLED;
+	else
+		return IRQ_NONE;
+}
+
+static int acp_dma_open(struct snd_pcm_substream *substream)
+{
+	u16 bank;
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *prtd = substream->private_data;
+	struct audio_drv_data *intr_data = dev_get_drvdata(prtd->platform->dev);
+
+	struct audio_substream_data *adata =
+		kzalloc(sizeof(struct audio_substream_data), GFP_KERNEL);
+	if (adata == NULL)
+		return -ENOMEM;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		runtime->hw = acp_pcm_hardware_playback;
+	else
+		runtime->hw = acp_pcm_hardware_capture;
+
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0) {
+		dev_err(prtd->platform->dev, "set integer constraint failed\n");
+		return ret;
+	}
+
+	adata->acp_mmio = intr_data->acp_mmio;
+	runtime->private_data = adata;
+
+	/* Enable ACP irq, when neither playback or capture streams are
+	 * active by the time when a new stream is being opened.
+	 * This enablement is not required for another stream, if current
+	 * stream is not closed
+	*/
+	if (!intr_data->play_stream && !intr_data->capture_stream)
+		acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		intr_data->play_stream = substream;
+		for (bank = 1; bank <= 4; bank++)
+			acp_set_sram_bank_state(intr_data->acp_mmio, bank,
+						true);
+	} else {
+		intr_data->capture_stream = substream;
+		for (bank = 5; bank <= 8; bank++)
+			acp_set_sram_bank_state(intr_data->acp_mmio, bank,
+						true);
+	}
+
+	return 0;
+}
+
+static int acp_dma_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	int status;
+	uint64_t size;
+	struct snd_dma_buffer *dma_buffer;
+	struct page *pg;
+	struct snd_pcm_runtime *runtime;
+	struct audio_substream_data *rtd;
+
+	dma_buffer = &substream->dma_buffer;
+
+	runtime = substream->runtime;
+	rtd = runtime->private_data;
+
+	if (WARN_ON(!rtd))
+		return -EINVAL;
+
+	size = params_buffer_bytes(params);
+	status = snd_pcm_lib_malloc_pages(substream, size);
+	if (status < 0)
+		return status;
+
+	memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
+	pg = virt_to_page(substream->dma_buffer.area);
+
+	if (pg != NULL) {
+		acp_set_sram_bank_state(rtd->acp_mmio, 0, true);
+		/* Save for runtime private data */
+		rtd->pg = pg;
+		rtd->order = get_order(size);
+
+		/* Fill the page table entries in ACP SRAM */
+		rtd->pg = pg;
+		rtd->size = size;
+		rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+		rtd->direction = substream->stream;
+
+		config_acp_dma(rtd->acp_mmio, rtd);
+		status = 0;
+	} else {
+		status = -ENOMEM;
+	}
+	return status;
+}
+
+static int acp_dma_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
+{
+	u16 dscr;
+	u32 mul, dma_config, period_bytes;
+	u32 pos = 0;
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_substream_data *rtd = runtime->private_data;
+
+	period_bytes = frames_to_bytes(runtime, runtime->period_size);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		dscr = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CUR_DSCR_13);
+
+		if (dscr == PLAYBACK_START_DMA_DESCR_CH13)
+			mul = 0;
+		else
+			mul = 1;
+		pos =  (mul * period_bytes);
+	} else {
+		dma_config = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CNTL_14);
+		if (dma_config != 0) {
+			dscr = acp_reg_read(rtd->acp_mmio,
+						mmACP_DMA_CUR_DSCR_14);
+			if (dscr == CAPTURE_START_DMA_DESCR_CH14)
+				mul = 1;
+			else
+				mul = 2;
+			pos = (mul * period_bytes);
+		}
+
+		if (pos >= (2 * period_bytes))
+			pos = 0;
+
+	}
+	return bytes_to_frames(runtime, pos);
+}
+
+static int acp_dma_mmap(struct snd_pcm_substream *substream,
+			struct vm_area_struct *vma)
+{
+	return snd_pcm_lib_default_mmap(substream, vma);
+}
+
+static int acp_dma_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_substream_data *rtd = runtime->private_data;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM,
+					PLAYBACK_START_DMA_DESCR_CH12,
+					NUM_DSCRS_PER_CHANNEL, 0);
+		config_acp_dma_channel(rtd->acp_mmio, ACP_TO_I2S_DMA_CH_NUM,
+					PLAYBACK_START_DMA_DESCR_CH13,
+					NUM_DSCRS_PER_CHANNEL, 0);
+		/* Fill ACP SRAM (2 periods) with zeros from System RAM
+		 * which is zero-ed in hw_params
+		*/
+		acp_dma_start(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM, false);
+
+		/* ACP SRAM (2 periods of buffer size) is intially filled with
+		 * zeros. Before rendering starts, 2nd half of SRAM will be
+		 * filled with valid audio data DMA'ed from first half of system
+		 * RAM and 1st half of SRAM will be filled with Zeros. This is
+		 * the initial scenario when redering starts from SRAM. Later
+		 * on, 2nd half of system memory will be DMA'ed to 1st half of
+		 * SRAM, 1st half of system memory will be DMA'ed to 2nd half of
+		 * SRAM in ping-pong way till rendering stops.
+		*/
+		config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM,
+					PLAYBACK_START_DMA_DESCR_CH12,
+					1, 0);
+	} else {
+		config_acp_dma_channel(rtd->acp_mmio, ACP_TO_SYSRAM_CH_NUM,
+					CAPTURE_START_DMA_DESCR_CH14,
+					NUM_DSCRS_PER_CHANNEL, 0);
+		config_acp_dma_channel(rtd->acp_mmio, I2S_TO_ACP_DMA_CH_NUM,
+					CAPTURE_START_DMA_DESCR_CH15,
+					NUM_DSCRS_PER_CHANNEL, 0);
+	}
+	return 0;
+}
+
+static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret;
+	u32 loops = 1000;
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *prtd = substream->private_data;
+	struct audio_substream_data *rtd = runtime->private_data;
+
+	if (!rtd)
+		return -EINVAL;
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			acp_dma_start(rtd->acp_mmio,
+						SYSRAM_TO_ACP_CH_NUM, false);
+			while (acp_reg_read(rtd->acp_mmio, mmACP_DMA_CH_STS) &
+						BIT(SYSRAM_TO_ACP_CH_NUM)) {
+				if (!loops--) {
+					dev_err(prtd->platform->dev,
+						"acp dma start timeout\n");
+					return -ETIMEDOUT;
+				}
+				cpu_relax();
+			}
+
+			acp_dma_start(rtd->acp_mmio,
+					ACP_TO_I2S_DMA_CH_NUM, true);
+
+		} else {
+			acp_dma_start(rtd->acp_mmio,
+					    I2S_TO_ACP_DMA_CH_NUM, true);
+		}
+		ret = 0;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		/* Need to stop only circular DMA channels :
+		 * ACP_TO_I2S_DMA_CH_NUM / I2S_TO_ACP_DMA_CH_NUM. Non-circular
+		 * channels will stopped automatically after its transfer
+		 * completes : SYSRAM_TO_ACP_CH_NUM / ACP_TO_SYSRAM_CH_NUM
+		 */
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			ret = acp_dma_stop(rtd->acp_mmio,
+					ACP_TO_I2S_DMA_CH_NUM);
+		else
+			ret = acp_dma_stop(rtd->acp_mmio,
+					I2S_TO_ACP_DMA_CH_NUM);
+		break;
+	default:
+		ret = -EINVAL;
+
+	}
+	return ret;
+}
+
+static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
+{
+	return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
+							SNDRV_DMA_TYPE_DEV,
+							NULL, MIN_BUFFER,
+							MAX_BUFFER);
+}
+
+static int acp_dma_close(struct snd_pcm_substream *substream)
+{
+	u16 bank;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_substream_data *rtd = runtime->private_data;
+	struct snd_soc_pcm_runtime *prtd = substream->private_data;
+	struct audio_drv_data *adata = dev_get_drvdata(prtd->platform->dev);
+
+	kfree(rtd);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		adata->play_stream = NULL;
+		for (bank = 1; bank <= 4; bank++)
+			acp_set_sram_bank_state(adata->acp_mmio, bank,
+						false);
+	} else {
+		adata->capture_stream = NULL;
+		for (bank = 5; bank <= 8; bank++)
+			acp_set_sram_bank_state(adata->acp_mmio, bank,
+						false);
+	}
+
+	/* Disable ACP irq, when the current stream is being closed and
+	 * another stream is also not active.
+	*/
+	if (!adata->play_stream && !adata->capture_stream)
+		acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
+
+	return 0;
+}
+
+static struct snd_pcm_ops acp_dma_ops = {
+	.open = acp_dma_open,
+	.close = acp_dma_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = acp_dma_hw_params,
+	.hw_free = acp_dma_hw_free,
+	.trigger = acp_dma_trigger,
+	.pointer = acp_dma_pointer,
+	.mmap = acp_dma_mmap,
+	.prepare = acp_dma_prepare,
+};
+
+static struct snd_soc_platform_driver acp_asoc_platform = {
+	.ops = &acp_dma_ops,
+	.pcm_new = acp_dma_new,
+};
+
+static int acp_audio_probe(struct platform_device *pdev)
+{
+	int status;
+	struct audio_drv_data *audio_drv_data;
+	struct resource *res;
+
+	audio_drv_data = devm_kzalloc(&pdev->dev, sizeof(struct audio_drv_data),
+					GFP_KERNEL);
+	if (audio_drv_data == NULL)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	audio_drv_data->acp_mmio = devm_ioremap_resource(&pdev->dev, res);
+
+	/* The following members gets populated in device 'open'
+	 * function. Till then interrupts are disabled in 'acp_init'
+	 * and device doesn't generate any interrupts.
+	 */
+
+	audio_drv_data->play_stream = NULL;
+	audio_drv_data->capture_stream = NULL;
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
+		return -ENODEV;
+	}
+
+	status = devm_request_irq(&pdev->dev, res->start, dma_irq_handler,
+					0, "ACP_IRQ", &pdev->dev);
+	if (status) {
+		dev_err(&pdev->dev, "ACP IRQ request failed\n");
+		return status;
+	}
+
+	dev_set_drvdata(&pdev->dev, audio_drv_data);
+
+	/* Initialize the ACP */
+	acp_init(audio_drv_data->acp_mmio);
+
+	status = snd_soc_register_platform(&pdev->dev, &acp_asoc_platform);
+	if (status != 0) {
+		dev_err(&pdev->dev, "Fail to register ALSA platform device\n");
+		return status;
+	}
+
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 10000);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	return status;
+}
+
+static int acp_audio_remove(struct platform_device *pdev)
+{
+	struct audio_drv_data *adata = dev_get_drvdata(&pdev->dev);
+
+	acp_deinit(adata->acp_mmio);
+	snd_soc_unregister_platform(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static int acp_pcm_resume(struct device *dev)
+{
+	u16 bank;
+	struct audio_drv_data *adata = dev_get_drvdata(dev);
+
+	acp_init(adata->acp_mmio);
+
+	if (adata->play_stream && adata->play_stream->runtime) {
+		for (bank = 1; bank <= 4; bank++)
+			acp_set_sram_bank_state(adata->acp_mmio, bank,
+						true);
+		config_acp_dma(adata->acp_mmio,
+				adata->play_stream->runtime->private_data);
+	}
+	if (adata->capture_stream && adata->capture_stream->runtime) {
+		for (bank = 5; bank <= 8; bank++)
+			acp_set_sram_bank_state(adata->acp_mmio, bank,
+						true);
+		config_acp_dma(adata->acp_mmio,
+				adata->capture_stream->runtime->private_data);
+	}
+	acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
+	return 0;
+}
+
+static int acp_pcm_runtime_suspend(struct device *dev)
+{
+	struct audio_drv_data *adata = dev_get_drvdata(dev);
+
+	acp_deinit(adata->acp_mmio);
+	acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
+	return 0;
+}
+
+static int acp_pcm_runtime_resume(struct device *dev)
+{
+	struct audio_drv_data *adata = dev_get_drvdata(dev);
+
+	acp_init(adata->acp_mmio);
+	acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
+	return 0;
+}
+
+static const struct dev_pm_ops acp_pm_ops = {
+	.resume = acp_pcm_resume,
+	.runtime_suspend = acp_pcm_runtime_suspend,
+	.runtime_resume = acp_pcm_runtime_resume,
+};
+
+static struct platform_driver acp_dma_driver = {
+	.probe = acp_audio_probe,
+	.remove = acp_audio_remove,
+	.driver = {
+		.name = "acp_audio_dma",
+		.pm = &acp_pm_ops,
+	},
+};
+
+module_platform_driver(acp_dma_driver);
+
+MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
+MODULE_DESCRIPTION("AMD ACP PCM Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:acp-dma-audio");
diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h
new file mode 100644
index 0000000..330832e
--- /dev/null
+++ b/sound/soc/amd/acp.h
@@ -0,0 +1,118 @@
+#ifndef __ACP_HW_H
+#define __ACP_HW_H
+
+#include "include/acp_2_2_d.h"
+#include "include/acp_2_2_sh_mask.h"
+
+#define ACP_PAGE_SIZE_4K_ENABLE			0x02
+
+#define ACP_PLAYBACK_PTE_OFFSET			10
+#define ACP_CAPTURE_PTE_OFFSET			0
+
+#define ACP_GARLIC_CNTL_DEFAULT			0x00000FB4
+#define ACP_ONION_CNTL_DEFAULT			0x00000FB4
+
+#define ACP_PHYSICAL_BASE			0x14000
+
+/* Playback SRAM address (as a destination in dma descriptor) */
+#define ACP_SHARED_RAM_BANK_1_ADDRESS		0x4002000
+
+/* Capture SRAM address (as a source in dma descriptor) */
+#define ACP_SHARED_RAM_BANK_5_ADDRESS		0x400A000
+
+#define ACP_DMA_RESET_TIME			10000
+#define ACP_CLOCK_EN_TIME_OUT_VALUE		0x000000FF
+#define ACP_SOFT_RESET_DONE_TIME_OUT_VALUE	0x000000FF
+#define ACP_DMA_COMPLETE_TIME_OUT_VALUE		0x000000FF
+
+#define ACP_SRAM_BASE_ADDRESS			0x4000000
+#define ACP_DAGB_GRP_SRAM_BASE_ADDRESS		0x4001000
+#define ACP_DAGB_GRP_SRBM_SRAM_BASE_OFFSET	0x1000
+#define ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS	0x00000000
+#define ACP_INTERNAL_APERTURE_WINDOW_4_ADDRESS	0x01800000
+
+#define TO_ACP_I2S_1   0x2
+#define TO_ACP_I2S_2   0x4
+#define FROM_ACP_I2S_1 0xa
+#define FROM_ACP_I2S_2 0xb
+
+#define ACP_TILE_ON_MASK                0x03
+#define ACP_TILE_OFF_MASK               0x02
+#define ACP_TILE_ON_RETAIN_REG_MASK     0x1f
+#define ACP_TILE_OFF_RETAIN_REG_MASK    0x20
+
+#define ACP_TILE_P1_MASK                0x3e
+#define ACP_TILE_P2_MASK                0x3d
+#define ACP_TILE_DSP0_MASK              0x3b
+#define ACP_TILE_DSP1_MASK              0x37
+
+#define ACP_TILE_DSP2_MASK              0x2f
+/* Playback DMA channels */
+#define SYSRAM_TO_ACP_CH_NUM 12
+#define ACP_TO_I2S_DMA_CH_NUM 13
+
+/* Capture DMA channels */
+#define ACP_TO_SYSRAM_CH_NUM 14
+#define I2S_TO_ACP_DMA_CH_NUM 15
+
+#define NUM_DSCRS_PER_CHANNEL 2
+
+#define PLAYBACK_START_DMA_DESCR_CH12 0
+#define PLAYBACK_END_DMA_DESCR_CH12 1
+#define PLAYBACK_START_DMA_DESCR_CH13 2
+#define PLAYBACK_END_DMA_DESCR_CH13 3
+
+#define CAPTURE_START_DMA_DESCR_CH14 4
+#define CAPTURE_END_DMA_DESCR_CH14 5
+#define CAPTURE_START_DMA_DESCR_CH15 6
+#define CAPTURE_END_DMA_DESCR_CH15 7
+
+enum acp_dma_priority_level {
+	/* 0x0 Specifies the DMA channel is given normal priority */
+	ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0,
+	/* 0x1 Specifies the DMA channel is given high priority */
+	ACP_DMA_PRIORITY_LEVEL_HIGH = 0x1,
+	ACP_DMA_PRIORITY_LEVEL_FORCESIZE = 0xFF
+};
+
+struct audio_substream_data {
+	struct page *pg;
+	unsigned int order;
+	u16 num_of_pages;
+	u16 direction;
+	uint64_t size;
+	void __iomem *acp_mmio;
+};
+
+enum {
+	ACP_TILE_P1 = 0,
+	ACP_TILE_P2,
+	ACP_TILE_DSP0,
+	ACP_TILE_DSP1,
+	ACP_TILE_DSP2,
+};
+
+enum {
+	ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION = 0x0,
+	ACP_DMA_ATTRIBUTES_SHARED_MEM_TO_DAGB_GARLIC = 0x1,
+	ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM = 0x8,
+	ACP_DMA_ATTRIBUTES_DAGB_GARLIC_TO_SHAREDMEM = 0x9,
+	ACP_DMA_ATTRIBUTES_FORCE_SIZE = 0xF
+};
+
+typedef struct acp_dma_dscr_transfer {
+	/* Specifies the source memory location for the DMA data transfer. */
+	u32 src;
+	/* Specifies the destination memory location to where the data will
+	 * be transferred.
+	*/
+	u32 dest;
+	/* Specifies the number of bytes need to be transferred
+	* from source to destination memory.Transfer direction & IOC enable
+	*/
+	u32 xfer_val;
+	/* Reserved for future use */
+	u32 reserved;
+} acp_dma_dscr_transfer_t;
+
+#endif /*__ACP_HW_H */
diff --git a/sound/soc/amd/include/acp_2_2_d.h b/sound/soc/amd/include/acp_2_2_d.h
new file mode 100644
index 0000000..0118fe9
--- /dev/null
+++ b/sound/soc/amd/include/acp_2_2_d.h
@@ -0,0 +1,609 @@
+/*
+ * ACP_2_2 Register documentation
+ *
+ * Copyright (C) 2014  Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef ACP_2_2_D_H
+#define ACP_2_2_D_H
+
+#define mmACP_DMA_CNTL_0                                                        0x5000
+#define mmACP_DMA_CNTL_1                                                        0x5001
+#define mmACP_DMA_CNTL_2                                                        0x5002
+#define mmACP_DMA_CNTL_3                                                        0x5003
+#define mmACP_DMA_CNTL_4                                                        0x5004
+#define mmACP_DMA_CNTL_5                                                        0x5005
+#define mmACP_DMA_CNTL_6                                                        0x5006
+#define mmACP_DMA_CNTL_7                                                        0x5007
+#define mmACP_DMA_CNTL_8                                                        0x5008
+#define mmACP_DMA_CNTL_9                                                        0x5009
+#define mmACP_DMA_CNTL_10                                                       0x500a
+#define mmACP_DMA_CNTL_11                                                       0x500b
+#define mmACP_DMA_CNTL_12                                                       0x500c
+#define mmACP_DMA_CNTL_13                                                       0x500d
+#define mmACP_DMA_CNTL_14                                                       0x500e
+#define mmACP_DMA_CNTL_15                                                       0x500f
+#define mmACP_DMA_DSCR_STRT_IDX_0                                               0x5010
+#define mmACP_DMA_DSCR_STRT_IDX_1                                               0x5011
+#define mmACP_DMA_DSCR_STRT_IDX_2                                               0x5012
+#define mmACP_DMA_DSCR_STRT_IDX_3                                               0x5013
+#define mmACP_DMA_DSCR_STRT_IDX_4                                               0x5014
+#define mmACP_DMA_DSCR_STRT_IDX_5                                               0x5015
+#define mmACP_DMA_DSCR_STRT_IDX_6                                               0x5016
+#define mmACP_DMA_DSCR_STRT_IDX_7                                               0x5017
+#define mmACP_DMA_DSCR_STRT_IDX_8                                               0x5018
+#define mmACP_DMA_DSCR_STRT_IDX_9                                               0x5019
+#define mmACP_DMA_DSCR_STRT_IDX_10                                              0x501a
+#define mmACP_DMA_DSCR_STRT_IDX_11                                              0x501b
+#define mmACP_DMA_DSCR_STRT_IDX_12                                              0x501c
+#define mmACP_DMA_DSCR_STRT_IDX_13                                              0x501d
+#define mmACP_DMA_DSCR_STRT_IDX_14                                              0x501e
+#define mmACP_DMA_DSCR_STRT_IDX_15                                              0x501f
+#define mmACP_DMA_DSCR_CNT_0                                                    0x5020
+#define mmACP_DMA_DSCR_CNT_1                                                    0x5021
+#define mmACP_DMA_DSCR_CNT_2                                                    0x5022
+#define mmACP_DMA_DSCR_CNT_3                                                    0x5023
+#define mmACP_DMA_DSCR_CNT_4                                                    0x5024
+#define mmACP_DMA_DSCR_CNT_5                                                    0x5025
+#define mmACP_DMA_DSCR_CNT_6                                                    0x5026
+#define mmACP_DMA_DSCR_CNT_7                                                    0x5027
+#define mmACP_DMA_DSCR_CNT_8                                                    0x5028
+#define mmACP_DMA_DSCR_CNT_9                                                    0x5029
+#define mmACP_DMA_DSCR_CNT_10                                                   0x502a
+#define mmACP_DMA_DSCR_CNT_11                                                   0x502b
+#define mmACP_DMA_DSCR_CNT_12                                                   0x502c
+#define mmACP_DMA_DSCR_CNT_13                                                   0x502d
+#define mmACP_DMA_DSCR_CNT_14                                                   0x502e
+#define mmACP_DMA_DSCR_CNT_15                                                   0x502f
+#define mmACP_DMA_PRIO_0                                                        0x5030
+#define mmACP_DMA_PRIO_1                                                        0x5031
+#define mmACP_DMA_PRIO_2                                                        0x5032
+#define mmACP_DMA_PRIO_3                                                        0x5033
+#define mmACP_DMA_PRIO_4                                                        0x5034
+#define mmACP_DMA_PRIO_5                                                        0x5035
+#define mmACP_DMA_PRIO_6                                                        0x5036
+#define mmACP_DMA_PRIO_7                                                        0x5037
+#define mmACP_DMA_PRIO_8                                                        0x5038
+#define mmACP_DMA_PRIO_9                                                        0x5039
+#define mmACP_DMA_PRIO_10                                                       0x503a
+#define mmACP_DMA_PRIO_11                                                       0x503b
+#define mmACP_DMA_PRIO_12                                                       0x503c
+#define mmACP_DMA_PRIO_13                                                       0x503d
+#define mmACP_DMA_PRIO_14                                                       0x503e
+#define mmACP_DMA_PRIO_15                                                       0x503f
+#define mmACP_DMA_CUR_DSCR_0                                                    0x5040
+#define mmACP_DMA_CUR_DSCR_1                                                    0x5041
+#define mmACP_DMA_CUR_DSCR_2                                                    0x5042
+#define mmACP_DMA_CUR_DSCR_3                                                    0x5043
+#define mmACP_DMA_CUR_DSCR_4                                                    0x5044
+#define mmACP_DMA_CUR_DSCR_5                                                    0x5045
+#define mmACP_DMA_CUR_DSCR_6                                                    0x5046
+#define mmACP_DMA_CUR_DSCR_7                                                    0x5047
+#define mmACP_DMA_CUR_DSCR_8                                                    0x5048
+#define mmACP_DMA_CUR_DSCR_9                                                    0x5049
+#define mmACP_DMA_CUR_DSCR_10                                                   0x504a
+#define mmACP_DMA_CUR_DSCR_11                                                   0x504b
+#define mmACP_DMA_CUR_DSCR_12                                                   0x504c
+#define mmACP_DMA_CUR_DSCR_13                                                   0x504d
+#define mmACP_DMA_CUR_DSCR_14                                                   0x504e
+#define mmACP_DMA_CUR_DSCR_15                                                   0x504f
+#define mmACP_DMA_CUR_TRANS_CNT_0                                               0x5050
+#define mmACP_DMA_CUR_TRANS_CNT_1                                               0x5051
+#define mmACP_DMA_CUR_TRANS_CNT_2                                               0x5052
+#define mmACP_DMA_CUR_TRANS_CNT_3                                               0x5053
+#define mmACP_DMA_CUR_TRANS_CNT_4                                               0x5054
+#define mmACP_DMA_CUR_TRANS_CNT_5                                               0x5055
+#define mmACP_DMA_CUR_TRANS_CNT_6                                               0x5056
+#define mmACP_DMA_CUR_TRANS_CNT_7                                               0x5057
+#define mmACP_DMA_CUR_TRANS_CNT_8                                               0x5058
+#define mmACP_DMA_CUR_TRANS_CNT_9                                               0x5059
+#define mmACP_DMA_CUR_TRANS_CNT_10                                              0x505a
+#define mmACP_DMA_CUR_TRANS_CNT_11                                              0x505b
+#define mmACP_DMA_CUR_TRANS_CNT_12                                              0x505c
+#define mmACP_DMA_CUR_TRANS_CNT_13                                              0x505d
+#define mmACP_DMA_CUR_TRANS_CNT_14                                              0x505e
+#define mmACP_DMA_CUR_TRANS_CNT_15                                              0x505f
+#define mmACP_DMA_ERR_STS_0                                                     0x5060
+#define mmACP_DMA_ERR_STS_1                                                     0x5061
+#define mmACP_DMA_ERR_STS_2                                                     0x5062
+#define mmACP_DMA_ERR_STS_3                                                     0x5063
+#define mmACP_DMA_ERR_STS_4                                                     0x5064
+#define mmACP_DMA_ERR_STS_5                                                     0x5065
+#define mmACP_DMA_ERR_STS_6                                                     0x5066
+#define mmACP_DMA_ERR_STS_7                                                     0x5067
+#define mmACP_DMA_ERR_STS_8                                                     0x5068
+#define mmACP_DMA_ERR_STS_9                                                     0x5069
+#define mmACP_DMA_ERR_STS_10                                                    0x506a
+#define mmACP_DMA_ERR_STS_11                                                    0x506b
+#define mmACP_DMA_ERR_STS_12                                                    0x506c
+#define mmACP_DMA_ERR_STS_13                                                    0x506d
+#define mmACP_DMA_ERR_STS_14                                                    0x506e
+#define mmACP_DMA_ERR_STS_15                                                    0x506f
+#define mmACP_DMA_DESC_BASE_ADDR                                                0x5070
+#define mmACP_DMA_DESC_MAX_NUM_DSCR                                             0x5071
+#define mmACP_DMA_CH_STS                                                        0x5072
+#define mmACP_DMA_CH_GROUP                                                      0x5073
+#define mmACP_DSP0_CACHE_OFFSET0                                                0x5078
+#define mmACP_DSP0_CACHE_SIZE0                                                  0x5079
+#define mmACP_DSP0_CACHE_OFFSET1                                                0x507a
+#define mmACP_DSP0_CACHE_SIZE1                                                  0x507b
+#define mmACP_DSP0_CACHE_OFFSET2                                                0x507c
+#define mmACP_DSP0_CACHE_SIZE2                                                  0x507d
+#define mmACP_DSP0_CACHE_OFFSET3                                                0x507e
+#define mmACP_DSP0_CACHE_SIZE3                                                  0x507f
+#define mmACP_DSP0_CACHE_OFFSET4                                                0x5080
+#define mmACP_DSP0_CACHE_SIZE4                                                  0x5081
+#define mmACP_DSP0_CACHE_OFFSET5                                                0x5082
+#define mmACP_DSP0_CACHE_SIZE5                                                  0x5083
+#define mmACP_DSP0_CACHE_OFFSET6                                                0x5084
+#define mmACP_DSP0_CACHE_SIZE6                                                  0x5085
+#define mmACP_DSP0_CACHE_OFFSET7                                                0x5086
+#define mmACP_DSP0_CACHE_SIZE7                                                  0x5087
+#define mmACP_DSP0_CACHE_OFFSET8                                                0x5088
+#define mmACP_DSP0_CACHE_SIZE8                                                  0x5089
+#define mmACP_DSP0_NONCACHE_OFFSET0                                             0x508a
+#define mmACP_DSP0_NONCACHE_SIZE0                                               0x508b
+#define mmACP_DSP0_NONCACHE_OFFSET1                                             0x508c
+#define mmACP_DSP0_NONCACHE_SIZE1                                               0x508d
+#define mmACP_DSP0_DEBUG_PC                                                     0x508e
+#define mmACP_DSP0_NMI_SEL                                                      0x508f
+#define mmACP_DSP0_CLKRST_CNTL                                                  0x5090
+#define mmACP_DSP0_RUNSTALL                                                     0x5091
+#define mmACP_DSP0_OCD_HALT_ON_RST                                              0x5092
+#define mmACP_DSP0_WAIT_MODE                                                    0x5093
+#define mmACP_DSP0_VECT_SEL                                                     0x5094
+#define mmACP_DSP0_DEBUG_REG1                                                   0x5095
+#define mmACP_DSP0_DEBUG_REG2                                                   0x5096
+#define mmACP_DSP0_DEBUG_REG3                                                   0x5097
+#define mmACP_DSP1_CACHE_OFFSET0                                                0x509d
+#define mmACP_DSP1_CACHE_SIZE0                                                  0x509e
+#define mmACP_DSP1_CACHE_OFFSET1                                                0x509f
+#define mmACP_DSP1_CACHE_SIZE1                                                  0x50a0
+#define mmACP_DSP1_CACHE_OFFSET2                                                0x50a1
+#define mmACP_DSP1_CACHE_SIZE2                                                  0x50a2
+#define mmACP_DSP1_CACHE_OFFSET3                                                0x50a3
+#define mmACP_DSP1_CACHE_SIZE3                                                  0x50a4
+#define mmACP_DSP1_CACHE_OFFSET4                                                0x50a5
+#define mmACP_DSP1_CACHE_SIZE4                                                  0x50a6
+#define mmACP_DSP1_CACHE_OFFSET5                                                0x50a7
+#define mmACP_DSP1_CACHE_SIZE5                                                  0x50a8
+#define mmACP_DSP1_CACHE_OFFSET6                                                0x50a9
+#define mmACP_DSP1_CACHE_SIZE6                                                  0x50aa
+#define mmACP_DSP1_CACHE_OFFSET7                                                0x50ab
+#define mmACP_DSP1_CACHE_SIZE7                                                  0x50ac
+#define mmACP_DSP1_CACHE_OFFSET8                                                0x50ad
+#define mmACP_DSP1_CACHE_SIZE8                                                  0x50ae
+#define mmACP_DSP1_NONCACHE_OFFSET0                                             0x50af
+#define mmACP_DSP1_NONCACHE_SIZE0                                               0x50b0
+#define mmACP_DSP1_NONCACHE_OFFSET1                                             0x50b1
+#define mmACP_DSP1_NONCACHE_SIZE1                                               0x50b2
+#define mmACP_DSP1_DEBUG_PC                                                     0x50b3
+#define mmACP_DSP1_NMI_SEL                                                      0x50b4
+#define mmACP_DSP1_CLKRST_CNTL                                                  0x50b5
+#define mmACP_DSP1_RUNSTALL                                                     0x50b6
+#define mmACP_DSP1_OCD_HALT_ON_RST                                              0x50b7
+#define mmACP_DSP1_WAIT_MODE                                                    0x50b8
+#define mmACP_DSP1_VECT_SEL                                                     0x50b9
+#define mmACP_DSP1_DEBUG_REG1                                                   0x50ba
+#define mmACP_DSP1_DEBUG_REG2                                                   0x50bb
+#define mmACP_DSP1_DEBUG_REG3                                                   0x50bc
+#define mmACP_DSP2_CACHE_OFFSET0                                                0x50c2
+#define mmACP_DSP2_CACHE_SIZE0                                                  0x50c3
+#define mmACP_DSP2_CACHE_OFFSET1                                                0x50c4
+#define mmACP_DSP2_CACHE_SIZE1                                                  0x50c5
+#define mmACP_DSP2_CACHE_OFFSET2                                                0x50c6
+#define mmACP_DSP2_CACHE_SIZE2                                                  0x50c7
+#define mmACP_DSP2_CACHE_OFFSET3                                                0x50c8
+#define mmACP_DSP2_CACHE_SIZE3                                                  0x50c9
+#define mmACP_DSP2_CACHE_OFFSET4                                                0x50ca
+#define mmACP_DSP2_CACHE_SIZE4                                                  0x50cb
+#define mmACP_DSP2_CACHE_OFFSET5                                                0x50cc
+#define mmACP_DSP2_CACHE_SIZE5                                                  0x50cd
+#define mmACP_DSP2_CACHE_OFFSET6                                                0x50ce
+#define mmACP_DSP2_CACHE_SIZE6                                                  0x50cf
+#define mmACP_DSP2_CACHE_OFFSET7                                                0x50d0
+#define mmACP_DSP2_CACHE_SIZE7                                                  0x50d1
+#define mmACP_DSP2_CACHE_OFFSET8                                                0x50d2
+#define mmACP_DSP2_CACHE_SIZE8                                                  0x50d3
+#define mmACP_DSP2_NONCACHE_OFFSET0                                             0x50d4
+#define mmACP_DSP2_NONCACHE_SIZE0                                               0x50d5
+#define mmACP_DSP2_NONCACHE_OFFSET1                                             0x50d6
+#define mmACP_DSP2_NONCACHE_SIZE1                                               0x50d7
+#define mmACP_DSP2_DEBUG_PC                                                     0x50d8
+#define mmACP_DSP2_NMI_SEL                                                      0x50d9
+#define mmACP_DSP2_CLKRST_CNTL                                                  0x50da
+#define mmACP_DSP2_RUNSTALL                                                     0x50db
+#define mmACP_DSP2_OCD_HALT_ON_RST                                              0x50dc
+#define mmACP_DSP2_WAIT_MODE                                                    0x50dd
+#define mmACP_DSP2_VECT_SEL                                                     0x50de
+#define mmACP_DSP2_DEBUG_REG1                                                   0x50df
+#define mmACP_DSP2_DEBUG_REG2                                                   0x50e0
+#define mmACP_DSP2_DEBUG_REG3                                                   0x50e1
+#define mmACP_AXI2DAGB_ONION_CNTL                                               0x50e7
+#define mmACP_AXI2DAGB_ONION_ERR_STATUS_WR                                      0x50e8
+#define mmACP_AXI2DAGB_ONION_ERR_STATUS_RD                                      0x50e9
+#define mmACP_DAGB_Onion_TransPerf_Counter_Control                              0x50ea
+#define mmACP_DAGB_Onion_Wr_TransPerf_Counter_Current                           0x50eb
+#define mmACP_DAGB_Onion_Wr_TransPerf_Counter_Peak                              0x50ec
+#define mmACP_DAGB_Onion_Rd_TransPerf_Counter_Current                           0x50ed
+#define mmACP_DAGB_Onion_Rd_TransPerf_Counter_Peak                              0x50ee
+#define mmACP_AXI2DAGB_GARLIC_CNTL                                              0x50f3
+#define mmACP_AXI2DAGB_GARLIC_ERR_STATUS_WR                                     0x50f4
+#define mmACP_AXI2DAGB_GARLIC_ERR_STATUS_RD                                     0x50f5
+#define mmACP_DAGB_Garlic_TransPerf_Counter_Control                             0x50f6
+#define mmACP_DAGB_Garlic_Wr_TransPerf_Counter_Current                          0x50f7
+#define mmACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak                             0x50f8
+#define mmACP_DAGB_Garlic_Rd_TransPerf_Counter_Current                          0x50f9
+#define mmACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak                             0x50fa
+#define mmACP_DAGB_PAGE_SIZE_GRP_1                                              0x50ff
+#define mmACP_DAGB_BASE_ADDR_GRP_1                                              0x5100
+#define mmACP_DAGB_PAGE_SIZE_GRP_2                                              0x5101
+#define mmACP_DAGB_BASE_ADDR_GRP_2                                              0x5102
+#define mmACP_DAGB_PAGE_SIZE_GRP_3                                              0x5103
+#define mmACP_DAGB_BASE_ADDR_GRP_3                                              0x5104
+#define mmACP_DAGB_PAGE_SIZE_GRP_4                                              0x5105
+#define mmACP_DAGB_BASE_ADDR_GRP_4                                              0x5106
+#define mmACP_DAGB_PAGE_SIZE_GRP_5                                              0x5107
+#define mmACP_DAGB_BASE_ADDR_GRP_5                                              0x5108
+#define mmACP_DAGB_PAGE_SIZE_GRP_6                                              0x5109
+#define mmACP_DAGB_BASE_ADDR_GRP_6                                              0x510a
+#define mmACP_DAGB_PAGE_SIZE_GRP_7                                              0x510b
+#define mmACP_DAGB_BASE_ADDR_GRP_7                                              0x510c
+#define mmACP_DAGB_PAGE_SIZE_GRP_8                                              0x510d
+#define mmACP_DAGB_BASE_ADDR_GRP_8                                              0x510e
+#define mmACP_DAGB_ATU_CTRL                                                     0x510f
+#define mmACP_CONTROL                                                           0x5131
+#define mmACP_STATUS                                                            0x5133
+#define mmACP_SOFT_RESET                                                        0x5134
+#define mmACP_PwrMgmt_CNTL                                                      0x5135
+#define mmACP_CAC_INDICATOR_CONTROL                                             0x5136
+#define mmACP_SMU_MAILBOX                                                       0x5137
+#define mmACP_FUTURE_REG_SCLK_0                                                 0x5138
+#define mmACP_FUTURE_REG_SCLK_1                                                 0x5139
+#define mmACP_FUTURE_REG_SCLK_2                                                 0x513a
+#define mmACP_FUTURE_REG_SCLK_3                                                 0x513b
+#define mmACP_FUTURE_REG_SCLK_4                                                 0x513c
+#define mmACP_DAGB_DEBUG_CNT_ENABLE                                             0x513d
+#define mmACP_DAGBG_WR_ASK_CNT                                                  0x513e
+#define mmACP_DAGBG_WR_GO_CNT                                                   0x513f
+#define mmACP_DAGBG_WR_EXP_RESP_CNT                                             0x5140
+#define mmACP_DAGBG_WR_ACTUAL_RESP_CNT                                          0x5141
+#define mmACP_DAGBG_RD_ASK_CNT                                                  0x5142
+#define mmACP_DAGBG_RD_GO_CNT                                                   0x5143
+#define mmACP_DAGBG_RD_EXP_RESP_CNT                                             0x5144
+#define mmACP_DAGBG_RD_ACTUAL_RESP_CNT                                          0x5145
+#define mmACP_DAGBO_WR_ASK_CNT                                                  0x5146
+#define mmACP_DAGBO_WR_GO_CNT                                                   0x5147
+#define mmACP_DAGBO_WR_EXP_RESP_CNT                                             0x5148
+#define mmACP_DAGBO_WR_ACTUAL_RESP_CNT                                          0x5149
+#define mmACP_DAGBO_RD_ASK_CNT                                                  0x514a
+#define mmACP_DAGBO_RD_GO_CNT                                                   0x514b
+#define mmACP_DAGBO_RD_EXP_RESP_CNT                                             0x514c
+#define mmACP_DAGBO_RD_ACTUAL_RESP_CNT                                          0x514d
+#define mmACP_BRB_CONTROL                                                       0x5156
+#define mmACP_EXTERNAL_INTR_ENB                                                 0x5157
+#define mmACP_EXTERNAL_INTR_CNTL                                                0x5158
+#define mmACP_ERROR_SOURCE_STS                                                  0x5159
+#define mmACP_DSP_SW_INTR_TRIG                                                  0x515a
+#define mmACP_DSP_SW_INTR_CNTL                                                  0x515b
+#define mmACP_DAGBG_TIMEOUT_CNTL                                                0x515c
+#define mmACP_DAGBO_TIMEOUT_CNTL                                                0x515d
+#define mmACP_EXTERNAL_INTR_STAT                                                0x515e
+#define mmACP_DSP_SW_INTR_STAT                                                  0x515f
+#define mmACP_DSP0_INTR_CNTL                                                    0x5160
+#define mmACP_DSP0_INTR_STAT                                                    0x5161
+#define mmACP_DSP0_TIMEOUT_CNTL                                                 0x5162
+#define mmACP_DSP1_INTR_CNTL                                                    0x5163
+#define mmACP_DSP1_INTR_STAT                                                    0x5164
+#define mmACP_DSP1_TIMEOUT_CNTL                                                 0x5165
+#define mmACP_DSP2_INTR_CNTL                                                    0x5166
+#define mmACP_DSP2_INTR_STAT                                                    0x5167
+#define mmACP_DSP2_TIMEOUT_CNTL                                                 0x5168
+#define mmACP_DSP0_EXT_TIMER_CNTL                                               0x5169
+#define mmACP_DSP1_EXT_TIMER_CNTL                                               0x516a
+#define mmACP_DSP2_EXT_TIMER_CNTL                                               0x516b
+#define mmACP_AXI2DAGB_SEM_0                                                    0x516c
+#define mmACP_AXI2DAGB_SEM_1                                                    0x516d
+#define mmACP_AXI2DAGB_SEM_2                                                    0x516e
+#define mmACP_AXI2DAGB_SEM_3                                                    0x516f
+#define mmACP_AXI2DAGB_SEM_4                                                    0x5170
+#define mmACP_AXI2DAGB_SEM_5                                                    0x5171
+#define mmACP_AXI2DAGB_SEM_6                                                    0x5172
+#define mmACP_AXI2DAGB_SEM_7                                                    0x5173
+#define mmACP_AXI2DAGB_SEM_8                                                    0x5174
+#define mmACP_AXI2DAGB_SEM_9                                                    0x5175
+#define mmACP_AXI2DAGB_SEM_10                                                   0x5176
+#define mmACP_AXI2DAGB_SEM_11                                                   0x5177
+#define mmACP_AXI2DAGB_SEM_12                                                   0x5178
+#define mmACP_AXI2DAGB_SEM_13                                                   0x5179
+#define mmACP_AXI2DAGB_SEM_14                                                   0x517a
+#define mmACP_AXI2DAGB_SEM_15                                                   0x517b
+#define mmACP_AXI2DAGB_SEM_16                                                   0x517c
+#define mmACP_AXI2DAGB_SEM_17                                                   0x517d
+#define mmACP_AXI2DAGB_SEM_18                                                   0x517e
+#define mmACP_AXI2DAGB_SEM_19                                                   0x517f
+#define mmACP_AXI2DAGB_SEM_20                                                   0x5180
+#define mmACP_AXI2DAGB_SEM_21                                                   0x5181
+#define mmACP_AXI2DAGB_SEM_22                                                   0x5182
+#define mmACP_AXI2DAGB_SEM_23                                                   0x5183
+#define mmACP_AXI2DAGB_SEM_24                                                   0x5184
+#define mmACP_AXI2DAGB_SEM_25                                                   0x5185
+#define mmACP_AXI2DAGB_SEM_26                                                   0x5186
+#define mmACP_AXI2DAGB_SEM_27                                                   0x5187
+#define mmACP_AXI2DAGB_SEM_28                                                   0x5188
+#define mmACP_AXI2DAGB_SEM_29                                                   0x5189
+#define mmACP_AXI2DAGB_SEM_30                                                   0x518a
+#define mmACP_AXI2DAGB_SEM_31                                                   0x518b
+#define mmACP_AXI2DAGB_SEM_32                                                   0x518c
+#define mmACP_AXI2DAGB_SEM_33                                                   0x518d
+#define mmACP_AXI2DAGB_SEM_34                                                   0x518e
+#define mmACP_AXI2DAGB_SEM_35                                                   0x518f
+#define mmACP_AXI2DAGB_SEM_36                                                   0x5190
+#define mmACP_AXI2DAGB_SEM_37                                                   0x5191
+#define mmACP_AXI2DAGB_SEM_38                                                   0x5192
+#define mmACP_AXI2DAGB_SEM_39                                                   0x5193
+#define mmACP_AXI2DAGB_SEM_40                                                   0x5194
+#define mmACP_AXI2DAGB_SEM_41                                                   0x5195
+#define mmACP_AXI2DAGB_SEM_42                                                   0x5196
+#define mmACP_AXI2DAGB_SEM_43                                                   0x5197
+#define mmACP_AXI2DAGB_SEM_44                                                   0x5198
+#define mmACP_AXI2DAGB_SEM_45                                                   0x5199
+#define mmACP_AXI2DAGB_SEM_46                                                   0x519a
+#define mmACP_AXI2DAGB_SEM_47                                                   0x519b
+#define mmACP_SRBM_Client_Base_Addr                                             0x519c
+#define mmACP_SRBM_Client_RDDATA                                                0x519d
+#define mmACP_SRBM_Cycle_Sts                                                    0x519e
+#define mmACP_SRBM_Targ_Idx_Addr                                                0x519f
+#define mmACP_SRBM_Targ_Idx_Data                                                0x51a0
+#define mmACP_SEMA_ADDR_LOW                                                     0x51a1
+#define mmACP_SEMA_ADDR_HIGH                                                    0x51a2
+#define mmACP_SEMA_CMD                                                          0x51a3
+#define mmACP_SEMA_STS                                                          0x51a4
+#define mmACP_SEMA_REQ                                                          0x51a5
+#define mmACP_FW_STATUS                                                         0x51a6
+#define mmACP_FUTURE_REG_ACLK_0                                                 0x51a7
+#define mmACP_FUTURE_REG_ACLK_1                                                 0x51a8
+#define mmACP_FUTURE_REG_ACLK_2                                                 0x51a9
+#define mmACP_FUTURE_REG_ACLK_3                                                 0x51aa
+#define mmACP_FUTURE_REG_ACLK_4                                                 0x51ab
+#define mmACP_TIMER                                                             0x51ac
+#define mmACP_TIMER_CNTL                                                        0x51ad
+#define mmACP_DSP0_TIMER                                                        0x51ae
+#define mmACP_DSP1_TIMER                                                        0x51af
+#define mmACP_DSP2_TIMER                                                        0x51b0
+#define mmACP_I2S_TRANSMIT_BYTE_CNT_HIGH                                        0x51b1
+#define mmACP_I2S_TRANSMIT_BYTE_CNT_LOW                                         0x51b2
+#define mmACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH                                     0x51b3
+#define mmACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW                                      0x51b4
+#define mmACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH                                      0x51b5
+#define mmACP_I2S_BT_RECEIVE_BYTE_CNT_LOW                                       0x51b6
+#define mmACP_DSP0_CS_STATE                                                     0x51b7
+#define mmACP_DSP1_CS_STATE                                                     0x51b8
+#define mmACP_DSP2_CS_STATE                                                     0x51b9
+#define mmACP_SCRATCH_REG_BASE_ADDR                                             0x51ba
+#define mmCC_ACP_EFUSE                                                          0x51c8
+#define mmACP_PGFSM_RETAIN_REG                                                  0x51c9
+#define mmACP_PGFSM_CONFIG_REG                                                  0x51ca
+#define mmACP_PGFSM_WRITE_REG                                                   0x51cb
+#define mmACP_PGFSM_READ_REG_0                                                  0x51cc
+#define mmACP_PGFSM_READ_REG_1                                                  0x51cd
+#define mmACP_PGFSM_READ_REG_2                                                  0x51ce
+#define mmACP_PGFSM_READ_REG_3                                                  0x51cf
+#define mmACP_PGFSM_READ_REG_4                                                  0x51d0
+#define mmACP_PGFSM_READ_REG_5                                                  0x51d1
+#define mmACP_IP_PGFSM_ENABLE                                                   0x51d2
+#define mmACP_I2S_PIN_CONFIG                                                    0x51d3
+#define mmACP_AZALIA_I2S_SELECT                                                 0x51d4
+#define mmACP_CHIP_PKG_FOR_PAD_ISOLATION                                        0x51d5
+#define mmACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL                                    0x51d6
+#define mmACP_BT_UART_PAD_SEL                                                   0x51d7
+#define mmACP_SCRATCH_REG_0                                                     0x52c0
+#define mmACP_SCRATCH_REG_1                                                     0x52c1
+#define mmACP_SCRATCH_REG_2                                                     0x52c2
+#define mmACP_SCRATCH_REG_3                                                     0x52c3
+#define mmACP_SCRATCH_REG_4                                                     0x52c4
+#define mmACP_SCRATCH_REG_5                                                     0x52c5
+#define mmACP_SCRATCH_REG_6                                                     0x52c6
+#define mmACP_SCRATCH_REG_7                                                     0x52c7
+#define mmACP_SCRATCH_REG_8                                                     0x52c8
+#define mmACP_SCRATCH_REG_9                                                     0x52c9
+#define mmACP_SCRATCH_REG_10                                                    0x52ca
+#define mmACP_SCRATCH_REG_11                                                    0x52cb
+#define mmACP_SCRATCH_REG_12                                                    0x52cc
+#define mmACP_SCRATCH_REG_13                                                    0x52cd
+#define mmACP_SCRATCH_REG_14                                                    0x52ce
+#define mmACP_SCRATCH_REG_15                                                    0x52cf
+#define mmACP_SCRATCH_REG_16                                                    0x52d0
+#define mmACP_SCRATCH_REG_17                                                    0x52d1
+#define mmACP_SCRATCH_REG_18                                                    0x52d2
+#define mmACP_SCRATCH_REG_19                                                    0x52d3
+#define mmACP_SCRATCH_REG_20                                                    0x52d4
+#define mmACP_SCRATCH_REG_21                                                    0x52d5
+#define mmACP_SCRATCH_REG_22                                                    0x52d6
+#define mmACP_SCRATCH_REG_23                                                    0x52d7
+#define mmACP_SCRATCH_REG_24                                                    0x52d8
+#define mmACP_SCRATCH_REG_25                                                    0x52d9
+#define mmACP_SCRATCH_REG_26                                                    0x52da
+#define mmACP_SCRATCH_REG_27                                                    0x52db
+#define mmACP_SCRATCH_REG_28                                                    0x52dc
+#define mmACP_SCRATCH_REG_29                                                    0x52dd
+#define mmACP_SCRATCH_REG_30                                                    0x52de
+#define mmACP_SCRATCH_REG_31                                                    0x52df
+#define mmACP_SCRATCH_REG_32                                                    0x52e0
+#define mmACP_SCRATCH_REG_33                                                    0x52e1
+#define mmACP_SCRATCH_REG_34                                                    0x52e2
+#define mmACP_SCRATCH_REG_35                                                    0x52e3
+#define mmACP_SCRATCH_REG_36                                                    0x52e4
+#define mmACP_SCRATCH_REG_37                                                    0x52e5
+#define mmACP_SCRATCH_REG_38                                                    0x52e6
+#define mmACP_SCRATCH_REG_39                                                    0x52e7
+#define mmACP_SCRATCH_REG_40                                                    0x52e8
+#define mmACP_SCRATCH_REG_41                                                    0x52e9
+#define mmACP_SCRATCH_REG_42                                                    0x52ea
+#define mmACP_SCRATCH_REG_43                                                    0x52eb
+#define mmACP_SCRATCH_REG_44                                                    0x52ec
+#define mmACP_SCRATCH_REG_45                                                    0x52ed
+#define mmACP_SCRATCH_REG_46                                                    0x52ee
+#define mmACP_SCRATCH_REG_47                                                    0x52ef
+#define mmACP_VOICE_WAKEUP_ENABLE                                               0x51e8
+#define mmACP_VOICE_WAKEUP_STATUS                                               0x51e9
+#define mmI2S_VOICE_WAKEUP_LOWER_THRESHOLD                                      0x51ea
+#define mmI2S_VOICE_WAKEUP_HIGHER_THRESHOLD                                     0x51eb
+#define mmI2S_VOICE_WAKEUP_NO_OF_SAMPLES                                        0x51ec
+#define mmI2S_VOICE_WAKEUP_NO_OF_PEAKS                                          0x51ed
+#define mmI2S_VOICE_WAKEUP_DURATION_OF_N_PEAKS                                  0x51ee
+#define mmI2S_VOICE_WAKEUP_BITCLK_TOGGLE_DETECTION                              0x51ef
+#define mmI2S_VOICE_WAKEUP_DATA_PATH_SWITCH                                     0x51f0
+#define mmI2S_VOICE_WAKEUP_DATA_POINTER                                         0x51f1
+#define mmI2S_VOICE_WAKEUP_AUTH_MATCH                                           0x51f2
+#define mmI2S_VOICE_WAKEUP_8KB_WRAP                                             0x51f3
+#define mmACP_I2S_RECEIVED_BYTE_CNT_HIGH                                        0x51f4
+#define mmACP_I2S_RECEIVED_BYTE_CNT_LOW                                         0x51f5
+#define mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH                                  0x51f6
+#define mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW                                   0x51f7
+#define mmACP_MEM_SHUT_DOWN_REQ_LO                                              0x51f8
+#define mmACP_MEM_SHUT_DOWN_REQ_HI                                              0x51f9
+#define mmACP_MEM_SHUT_DOWN_STS_LO                                              0x51fa
+#define mmACP_MEM_SHUT_DOWN_STS_HI                                              0x51fb
+#define mmACP_MEM_DEEP_SLEEP_REQ_LO                                             0x51fc
+#define mmACP_MEM_DEEP_SLEEP_REQ_HI                                             0x51fd
+#define mmACP_MEM_DEEP_SLEEP_STS_LO                                             0x51fe
+#define mmACP_MEM_DEEP_SLEEP_STS_HI                                             0x51ff
+#define mmACP_MEM_WAKEUP_FROM_SHUT_DOWN_LO                                      0x5200
+#define mmACP_MEM_WAKEUP_FROM_SHUT_DOWN_HI                                      0x5201
+#define mmACP_MEM_WAKEUP_FROM_SLEEP_LO                                          0x5202
+#define mmACP_MEM_WAKEUP_FROM_SLEEP_HI                                          0x5203
+#define mmACP_I2SSP_IER                                                         0x5210
+#define mmACP_I2SSP_IRER                                                        0x5211
+#define mmACP_I2SSP_ITER                                                        0x5212
+#define mmACP_I2SSP_CER                                                         0x5213
+#define mmACP_I2SSP_CCR                                                         0x5214
+#define mmACP_I2SSP_RXFFR                                                       0x5215
+#define mmACP_I2SSP_TXFFR                                                       0x5216
+#define mmACP_I2SSP_LRBR0                                                       0x5218
+#define mmACP_I2SSP_RRBR0                                                       0x5219
+#define mmACP_I2SSP_RER0                                                        0x521a
+#define mmACP_I2SSP_TER0                                                        0x521b
+#define mmACP_I2SSP_RCR0                                                        0x521c
+#define mmACP_I2SSP_TCR0                                                        0x521d
+#define mmACP_I2SSP_ISR0                                                        0x521e
+#define mmACP_I2SSP_IMR0                                                        0x521f
+#define mmACP_I2SSP_ROR0                                                        0x5220
+#define mmACP_I2SSP_TOR0                                                        0x5221
+#define mmACP_I2SSP_RFCR0                                                       0x5222
+#define mmACP_I2SSP_TFCR0                                                       0x5223
+#define mmACP_I2SSP_RFF0                                                        0x5224
+#define mmACP_I2SSP_TFF0                                                        0x5225
+#define mmACP_I2SSP_RXDMA                                                       0x5226
+#define mmACP_I2SSP_RRXDMA                                                      0x5227
+#define mmACP_I2SSP_TXDMA                                                       0x5228
+#define mmACP_I2SSP_RTXDMA                                                      0x5229
+#define mmACP_I2SSP_COMP_PARAM_2                                                0x522a
+#define mmACP_I2SSP_COMP_PARAM_1                                                0x522b
+#define mmACP_I2SSP_COMP_VERSION                                                0x522c
+#define mmACP_I2SSP_COMP_TYPE                                                   0x522d
+#define mmACP_I2SMICSP_IER                                                      0x522e
+#define mmACP_I2SMICSP_IRER                                                     0x522f
+#define mmACP_I2SMICSP_ITER                                                     0x5230
+#define mmACP_I2SMICSP_CER                                                      0x5231
+#define mmACP_I2SMICSP_CCR                                                      0x5232
+#define mmACP_I2SMICSP_RXFFR                                                    0x5233
+#define mmACP_I2SMICSP_TXFFR                                                    0x5234
+#define mmACP_I2SMICSP_LRBR0                                                    0x5236
+#define mmACP_I2SMICSP_RRBR0                                                    0x5237
+#define mmACP_I2SMICSP_RER0                                                     0x5238
+#define mmACP_I2SMICSP_TER0                                                     0x5239
+#define mmACP_I2SMICSP_RCR0                                                     0x523a
+#define mmACP_I2SMICSP_TCR0                                                     0x523b
+#define mmACP_I2SMICSP_ISR0                                                     0x523c
+#define mmACP_I2SMICSP_IMR0                                                     0x523d
+#define mmACP_I2SMICSP_ROR0                                                     0x523e
+#define mmACP_I2SMICSP_TOR0                                                     0x523f
+#define mmACP_I2SMICSP_RFCR0                                                    0x5240
+#define mmACP_I2SMICSP_TFCR0                                                    0x5241
+#define mmACP_I2SMICSP_RFF0                                                     0x5242
+#define mmACP_I2SMICSP_TFF0                                                     0x5243
+#define mmACP_I2SMICSP_LRBR1                                                    0x5246
+#define mmACP_I2SMICSP_RRBR1                                                    0x5247
+#define mmACP_I2SMICSP_RER1                                                     0x5248
+#define mmACP_I2SMICSP_TER1                                                     0x5249
+#define mmACP_I2SMICSP_RCR1                                                     0x524a
+#define mmACP_I2SMICSP_TCR1                                                     0x524b
+#define mmACP_I2SMICSP_ISR1                                                     0x524c
+#define mmACP_I2SMICSP_IMR1                                                     0x524d
+#define mmACP_I2SMICSP_ROR1                                                     0x524e
+#define mmACP_I2SMICSP_TOR1                                                     0x524f
+#define mmACP_I2SMICSP_RFCR1                                                    0x5250
+#define mmACP_I2SMICSP_TFCR1                                                    0x5251
+#define mmACP_I2SMICSP_RFF1                                                     0x5252
+#define mmACP_I2SMICSP_TFF1                                                     0x5253
+#define mmACP_I2SMICSP_RXDMA                                                    0x5254
+#define mmACP_I2SMICSP_RRXDMA                                                   0x5255
+#define mmACP_I2SMICSP_TXDMA                                                    0x5256
+#define mmACP_I2SMICSP_RTXDMA                                                   0x5257
+#define mmACP_I2SMICSP_COMP_PARAM_2                                             0x5258
+#define mmACP_I2SMICSP_COMP_PARAM_1                                             0x5259
+#define mmACP_I2SMICSP_COMP_VERSION                                             0x525a
+#define mmACP_I2SMICSP_COMP_TYPE                                                0x525b
+#define mmACP_I2SBT_IER                                                         0x525c
+#define mmACP_I2SBT_IRER                                                        0x525d
+#define mmACP_I2SBT_ITER                                                        0x525e
+#define mmACP_I2SBT_CER                                                         0x525f
+#define mmACP_I2SBT_CCR                                                         0x5260
+#define mmACP_I2SBT_RXFFR                                                       0x5261
+#define mmACP_I2SBT_TXFFR                                                       0x5262
+#define mmACP_I2SBT_LRBR0                                                       0x5264
+#define mmACP_I2SBT_RRBR0                                                       0x5265
+#define mmACP_I2SBT_RER0                                                        0x5266
+#define mmACP_I2SBT_TER0                                                        0x5267
+#define mmACP_I2SBT_RCR0                                                        0x5268
+#define mmACP_I2SBT_TCR0                                                        0x5269
+#define mmACP_I2SBT_ISR0                                                        0x526a
+#define mmACP_I2SBT_IMR0                                                        0x526b
+#define mmACP_I2SBT_ROR0                                                        0x526c
+#define mmACP_I2SBT_TOR0                                                        0x526d
+#define mmACP_I2SBT_RFCR0                                                       0x526e
+#define mmACP_I2SBT_TFCR0                                                       0x526f
+#define mmACP_I2SBT_RFF0                                                        0x5270
+#define mmACP_I2SBT_TFF0                                                        0x5271
+#define mmACP_I2SBT_LRBR1                                                       0x5274
+#define mmACP_I2SBT_RRBR1                                                       0x5275
+#define mmACP_I2SBT_RER1                                                        0x5276
+#define mmACP_I2SBT_TER1                                                        0x5277
+#define mmACP_I2SBT_RCR1                                                        0x5278
+#define mmACP_I2SBT_TCR1                                                        0x5279
+#define mmACP_I2SBT_ISR1                                                        0x527a
+#define mmACP_I2SBT_IMR1                                                        0x527b
+#define mmACP_I2SBT_ROR1                                                        0x527c
+#define mmACP_I2SBT_TOR1                                                        0x527d
+#define mmACP_I2SBT_RFCR1                                                       0x527e
+#define mmACP_I2SBT_TFCR1                                                       0x527f
+#define mmACP_I2SBT_RFF1                                                        0x5280
+#define mmACP_I2SBT_TFF1                                                        0x5281
+#define mmACP_I2SBT_RXDMA                                                       0x5282
+#define mmACP_I2SBT_RRXDMA                                                      0x5283
+#define mmACP_I2SBT_TXDMA                                                       0x5284
+#define mmACP_I2SBT_RTXDMA                                                      0x5285
+#define mmACP_I2SBT_COMP_PARAM_2                                                0x5286
+#define mmACP_I2SBT_COMP_PARAM_1                                                0x5287
+#define mmACP_I2SBT_COMP_VERSION                                                0x5288
+#define mmACP_I2SBT_COMP_TYPE                                                   0x5289
+
+#endif /* ACP_2_2_D_H */
diff --git a/sound/soc/amd/include/acp_2_2_enum.h b/sound/soc/amd/include/acp_2_2_enum.h
new file mode 100644
index 0000000..f3577c8
--- /dev/null
+++ b/sound/soc/amd/include/acp_2_2_enum.h
@@ -0,0 +1,1068 @@
+/*
+ * ACP_2_2 Register documentation
+ *
+ * Copyright (C) 2014  Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef ACP_2_2_ENUM_H
+#define ACP_2_2_ENUM_H
+
+typedef enum DebugBlockId {
+	DBG_BLOCK_ID_RESERVED                            = 0x0,
+	DBG_BLOCK_ID_DBG                                 = 0x1,
+	DBG_BLOCK_ID_VMC                                 = 0x2,
+	DBG_BLOCK_ID_PDMA                                = 0x3,
+	DBG_BLOCK_ID_CG                                  = 0x4,
+	DBG_BLOCK_ID_SRBM                                = 0x5,
+	DBG_BLOCK_ID_GRBM                                = 0x6,
+	DBG_BLOCK_ID_RLC                                 = 0x7,
+	DBG_BLOCK_ID_CSC                                 = 0x8,
+	DBG_BLOCK_ID_SEM                                 = 0x9,
+	DBG_BLOCK_ID_IH                                  = 0xa,
+	DBG_BLOCK_ID_SC                                  = 0xb,
+	DBG_BLOCK_ID_SQ                                  = 0xc,
+	DBG_BLOCK_ID_UVDU                                = 0xd,
+	DBG_BLOCK_ID_SQA                                 = 0xe,
+	DBG_BLOCK_ID_SDMA0                               = 0xf,
+	DBG_BLOCK_ID_SDMA1                               = 0x10,
+	DBG_BLOCK_ID_SPIM                                = 0x11,
+	DBG_BLOCK_ID_GDS                                 = 0x12,
+	DBG_BLOCK_ID_VC0                                 = 0x13,
+	DBG_BLOCK_ID_VC1                                 = 0x14,
+	DBG_BLOCK_ID_PA0                                 = 0x15,
+	DBG_BLOCK_ID_PA1                                 = 0x16,
+	DBG_BLOCK_ID_CP0                                 = 0x17,
+	DBG_BLOCK_ID_CP1                                 = 0x18,
+	DBG_BLOCK_ID_CP2                                 = 0x19,
+	DBG_BLOCK_ID_XBR                                 = 0x1a,
+	DBG_BLOCK_ID_UVDM                                = 0x1b,
+	DBG_BLOCK_ID_VGT0                                = 0x1c,
+	DBG_BLOCK_ID_VGT1                                = 0x1d,
+	DBG_BLOCK_ID_IA                                  = 0x1e,
+	DBG_BLOCK_ID_SXM0                                = 0x1f,
+	DBG_BLOCK_ID_SXM1                                = 0x20,
+	DBG_BLOCK_ID_SCT0                                = 0x21,
+	DBG_BLOCK_ID_SCT1                                = 0x22,
+	DBG_BLOCK_ID_SPM0                                = 0x23,
+	DBG_BLOCK_ID_SPM1                                = 0x24,
+	DBG_BLOCK_ID_UNUSED0                             = 0x25,
+	DBG_BLOCK_ID_UNUSED1                             = 0x26,
+	DBG_BLOCK_ID_TCAA                                = 0x27,
+	DBG_BLOCK_ID_TCAB                                = 0x28,
+	DBG_BLOCK_ID_TCCA                                = 0x29,
+	DBG_BLOCK_ID_TCCB                                = 0x2a,
+	DBG_BLOCK_ID_MCC0                                = 0x2b,
+	DBG_BLOCK_ID_MCC1                                = 0x2c,
+	DBG_BLOCK_ID_MCC2                                = 0x2d,
+	DBG_BLOCK_ID_MCC3                                = 0x2e,
+	DBG_BLOCK_ID_SXS0                                = 0x2f,
+	DBG_BLOCK_ID_SXS1                                = 0x30,
+	DBG_BLOCK_ID_SXS2                                = 0x31,
+	DBG_BLOCK_ID_SXS3                                = 0x32,
+	DBG_BLOCK_ID_SXS4                                = 0x33,
+	DBG_BLOCK_ID_SXS5                                = 0x34,
+	DBG_BLOCK_ID_SXS6                                = 0x35,
+	DBG_BLOCK_ID_SXS7                                = 0x36,
+	DBG_BLOCK_ID_SXS8                                = 0x37,
+	DBG_BLOCK_ID_SXS9                                = 0x38,
+	DBG_BLOCK_ID_BCI0                                = 0x39,
+	DBG_BLOCK_ID_BCI1                                = 0x3a,
+	DBG_BLOCK_ID_BCI2                                = 0x3b,
+	DBG_BLOCK_ID_BCI3                                = 0x3c,
+	DBG_BLOCK_ID_MCB                                 = 0x3d,
+	DBG_BLOCK_ID_UNUSED6                             = 0x3e,
+	DBG_BLOCK_ID_SQA00                               = 0x3f,
+	DBG_BLOCK_ID_SQA01                               = 0x40,
+	DBG_BLOCK_ID_SQA02                               = 0x41,
+	DBG_BLOCK_ID_SQA10                               = 0x42,
+	DBG_BLOCK_ID_SQA11                               = 0x43,
+	DBG_BLOCK_ID_SQA12                               = 0x44,
+	DBG_BLOCK_ID_UNUSED7                             = 0x45,
+	DBG_BLOCK_ID_UNUSED8                             = 0x46,
+	DBG_BLOCK_ID_SQB00                               = 0x47,
+	DBG_BLOCK_ID_SQB01                               = 0x48,
+	DBG_BLOCK_ID_SQB10                               = 0x49,
+	DBG_BLOCK_ID_SQB11                               = 0x4a,
+	DBG_BLOCK_ID_SQ00                                = 0x4b,
+	DBG_BLOCK_ID_SQ01                                = 0x4c,
+	DBG_BLOCK_ID_SQ10                                = 0x4d,
+	DBG_BLOCK_ID_SQ11                                = 0x4e,
+	DBG_BLOCK_ID_CB00                                = 0x4f,
+	DBG_BLOCK_ID_CB01                                = 0x50,
+	DBG_BLOCK_ID_CB02                                = 0x51,
+	DBG_BLOCK_ID_CB03                                = 0x52,
+	DBG_BLOCK_ID_CB04                                = 0x53,
+	DBG_BLOCK_ID_UNUSED9                             = 0x54,
+	DBG_BLOCK_ID_UNUSED10                            = 0x55,
+	DBG_BLOCK_ID_UNUSED11                            = 0x56,
+	DBG_BLOCK_ID_CB10                                = 0x57,
+	DBG_BLOCK_ID_CB11                                = 0x58,
+	DBG_BLOCK_ID_CB12                                = 0x59,
+	DBG_BLOCK_ID_CB13                                = 0x5a,
+	DBG_BLOCK_ID_CB14                                = 0x5b,
+	DBG_BLOCK_ID_UNUSED12                            = 0x5c,
+	DBG_BLOCK_ID_UNUSED13                            = 0x5d,
+	DBG_BLOCK_ID_UNUSED14                            = 0x5e,
+	DBG_BLOCK_ID_TCP0                                = 0x5f,
+	DBG_BLOCK_ID_TCP1                                = 0x60,
+	DBG_BLOCK_ID_TCP2                                = 0x61,
+	DBG_BLOCK_ID_TCP3                                = 0x62,
+	DBG_BLOCK_ID_TCP4                                = 0x63,
+	DBG_BLOCK_ID_TCP5                                = 0x64,
+	DBG_BLOCK_ID_TCP6                                = 0x65,
+	DBG_BLOCK_ID_TCP7                                = 0x66,
+	DBG_BLOCK_ID_TCP8                                = 0x67,
+	DBG_BLOCK_ID_TCP9                                = 0x68,
+	DBG_BLOCK_ID_TCP10                               = 0x69,
+	DBG_BLOCK_ID_TCP11                               = 0x6a,
+	DBG_BLOCK_ID_TCP12                               = 0x6b,
+	DBG_BLOCK_ID_TCP13                               = 0x6c,
+	DBG_BLOCK_ID_TCP14                               = 0x6d,
+	DBG_BLOCK_ID_TCP15                               = 0x6e,
+	DBG_BLOCK_ID_TCP16                               = 0x6f,
+	DBG_BLOCK_ID_TCP17                               = 0x70,
+	DBG_BLOCK_ID_TCP18                               = 0x71,
+	DBG_BLOCK_ID_TCP19                               = 0x72,
+	DBG_BLOCK_ID_TCP20                               = 0x73,
+	DBG_BLOCK_ID_TCP21                               = 0x74,
+	DBG_BLOCK_ID_TCP22                               = 0x75,
+	DBG_BLOCK_ID_TCP23                               = 0x76,
+	DBG_BLOCK_ID_TCP_RESERVED0                       = 0x77,
+	DBG_BLOCK_ID_TCP_RESERVED1                       = 0x78,
+	DBG_BLOCK_ID_TCP_RESERVED2                       = 0x79,
+	DBG_BLOCK_ID_TCP_RESERVED3                       = 0x7a,
+	DBG_BLOCK_ID_TCP_RESERVED4                       = 0x7b,
+	DBG_BLOCK_ID_TCP_RESERVED5                       = 0x7c,
+	DBG_BLOCK_ID_TCP_RESERVED6                       = 0x7d,
+	DBG_BLOCK_ID_TCP_RESERVED7                       = 0x7e,
+	DBG_BLOCK_ID_DB00                                = 0x7f,
+	DBG_BLOCK_ID_DB01                                = 0x80,
+	DBG_BLOCK_ID_DB02                                = 0x81,
+	DBG_BLOCK_ID_DB03                                = 0x82,
+	DBG_BLOCK_ID_DB04                                = 0x83,
+	DBG_BLOCK_ID_UNUSED15                            = 0x84,
+	DBG_BLOCK_ID_UNUSED16                            = 0x85,
+	DBG_BLOCK_ID_UNUSED17                            = 0x86,
+	DBG_BLOCK_ID_DB10                                = 0x87,
+	DBG_BLOCK_ID_DB11                                = 0x88,
+	DBG_BLOCK_ID_DB12                                = 0x89,
+	DBG_BLOCK_ID_DB13                                = 0x8a,
+	DBG_BLOCK_ID_DB14                                = 0x8b,
+	DBG_BLOCK_ID_UNUSED18                            = 0x8c,
+	DBG_BLOCK_ID_UNUSED19                            = 0x8d,
+	DBG_BLOCK_ID_UNUSED20                            = 0x8e,
+	DBG_BLOCK_ID_TCC0                                = 0x8f,
+	DBG_BLOCK_ID_TCC1                                = 0x90,
+	DBG_BLOCK_ID_TCC2                                = 0x91,
+	DBG_BLOCK_ID_TCC3                                = 0x92,
+	DBG_BLOCK_ID_TCC4                                = 0x93,
+	DBG_BLOCK_ID_TCC5                                = 0x94,
+	DBG_BLOCK_ID_TCC6                                = 0x95,
+	DBG_BLOCK_ID_TCC7                                = 0x96,
+	DBG_BLOCK_ID_SPS00                               = 0x97,
+	DBG_BLOCK_ID_SPS01                               = 0x98,
+	DBG_BLOCK_ID_SPS02                               = 0x99,
+	DBG_BLOCK_ID_SPS10                               = 0x9a,
+	DBG_BLOCK_ID_SPS11                               = 0x9b,
+	DBG_BLOCK_ID_SPS12                               = 0x9c,
+	DBG_BLOCK_ID_UNUSED21                            = 0x9d,
+	DBG_BLOCK_ID_UNUSED22                            = 0x9e,
+	DBG_BLOCK_ID_TA00                                = 0x9f,
+	DBG_BLOCK_ID_TA01                                = 0xa0,
+	DBG_BLOCK_ID_TA02                                = 0xa1,
+	DBG_BLOCK_ID_TA03                                = 0xa2,
+	DBG_BLOCK_ID_TA04                                = 0xa3,
+	DBG_BLOCK_ID_TA05                                = 0xa4,
+	DBG_BLOCK_ID_TA06                                = 0xa5,
+	DBG_BLOCK_ID_TA07                                = 0xa6,
+	DBG_BLOCK_ID_TA08                                = 0xa7,
+	DBG_BLOCK_ID_TA09                                = 0xa8,
+	DBG_BLOCK_ID_TA0A                                = 0xa9,
+	DBG_BLOCK_ID_TA0B                                = 0xaa,
+	DBG_BLOCK_ID_UNUSED23                            = 0xab,
+	DBG_BLOCK_ID_UNUSED24                            = 0xac,
+	DBG_BLOCK_ID_UNUSED25                            = 0xad,
+	DBG_BLOCK_ID_UNUSED26                            = 0xae,
+	DBG_BLOCK_ID_TA10                                = 0xaf,
+	DBG_BLOCK_ID_TA11                                = 0xb0,
+	DBG_BLOCK_ID_TA12                                = 0xb1,
+	DBG_BLOCK_ID_TA13                                = 0xb2,
+	DBG_BLOCK_ID_TA14                                = 0xb3,
+	DBG_BLOCK_ID_TA15                                = 0xb4,
+	DBG_BLOCK_ID_TA16                                = 0xb5,
+	DBG_BLOCK_ID_TA17                                = 0xb6,
+	DBG_BLOCK_ID_TA18                                = 0xb7,
+	DBG_BLOCK_ID_TA19                                = 0xb8,
+	DBG_BLOCK_ID_TA1A                                = 0xb9,
+	DBG_BLOCK_ID_TA1B                                = 0xba,
+	DBG_BLOCK_ID_UNUSED27                            = 0xbb,
+	DBG_BLOCK_ID_UNUSED28                            = 0xbc,
+	DBG_BLOCK_ID_UNUSED29                            = 0xbd,
+	DBG_BLOCK_ID_UNUSED30                            = 0xbe,
+	DBG_BLOCK_ID_TD00                                = 0xbf,
+	DBG_BLOCK_ID_TD01                                = 0xc0,
+	DBG_BLOCK_ID_TD02                                = 0xc1,
+	DBG_BLOCK_ID_TD03                                = 0xc2,
+	DBG_BLOCK_ID_TD04                                = 0xc3,
+	DBG_BLOCK_ID_TD05                                = 0xc4,
+	DBG_BLOCK_ID_TD06                                = 0xc5,
+	DBG_BLOCK_ID_TD07                                = 0xc6,
+	DBG_BLOCK_ID_TD08                                = 0xc7,
+	DBG_BLOCK_ID_TD09                                = 0xc8,
+	DBG_BLOCK_ID_TD0A                                = 0xc9,
+	DBG_BLOCK_ID_TD0B                                = 0xca,
+	DBG_BLOCK_ID_UNUSED31                            = 0xcb,
+	DBG_BLOCK_ID_UNUSED32                            = 0xcc,
+	DBG_BLOCK_ID_UNUSED33                            = 0xcd,
+	DBG_BLOCK_ID_UNUSED34                            = 0xce,
+	DBG_BLOCK_ID_TD10                                = 0xcf,
+	DBG_BLOCK_ID_TD11                                = 0xd0,
+	DBG_BLOCK_ID_TD12                                = 0xd1,
+	DBG_BLOCK_ID_TD13                                = 0xd2,
+	DBG_BLOCK_ID_TD14                                = 0xd3,
+	DBG_BLOCK_ID_TD15                                = 0xd4,
+	DBG_BLOCK_ID_TD16                                = 0xd5,
+	DBG_BLOCK_ID_TD17                                = 0xd6,
+	DBG_BLOCK_ID_TD18                                = 0xd7,
+	DBG_BLOCK_ID_TD19                                = 0xd8,
+	DBG_BLOCK_ID_TD1A                                = 0xd9,
+	DBG_BLOCK_ID_TD1B                                = 0xda,
+	DBG_BLOCK_ID_UNUSED35                            = 0xdb,
+	DBG_BLOCK_ID_UNUSED36                            = 0xdc,
+	DBG_BLOCK_ID_UNUSED37                            = 0xdd,
+	DBG_BLOCK_ID_UNUSED38                            = 0xde,
+	DBG_BLOCK_ID_LDS00                               = 0xdf,
+	DBG_BLOCK_ID_LDS01                               = 0xe0,
+	DBG_BLOCK_ID_LDS02                               = 0xe1,
+	DBG_BLOCK_ID_LDS03                               = 0xe2,
+	DBG_BLOCK_ID_LDS04                               = 0xe3,
+	DBG_BLOCK_ID_LDS05                               = 0xe4,
+	DBG_BLOCK_ID_LDS06                               = 0xe5,
+	DBG_BLOCK_ID_LDS07                               = 0xe6,
+	DBG_BLOCK_ID_LDS08                               = 0xe7,
+	DBG_BLOCK_ID_LDS09                               = 0xe8,
+	DBG_BLOCK_ID_LDS0A                               = 0xe9,
+	DBG_BLOCK_ID_LDS0B                               = 0xea,
+	DBG_BLOCK_ID_UNUSED39                            = 0xeb,
+	DBG_BLOCK_ID_UNUSED40                            = 0xec,
+	DBG_BLOCK_ID_UNUSED41                            = 0xed,
+	DBG_BLOCK_ID_UNUSED42                            = 0xee,
+	DBG_BLOCK_ID_LDS10                               = 0xef,
+	DBG_BLOCK_ID_LDS11                               = 0xf0,
+	DBG_BLOCK_ID_LDS12                               = 0xf1,
+	DBG_BLOCK_ID_LDS13                               = 0xf2,
+	DBG_BLOCK_ID_LDS14                               = 0xf3,
+	DBG_BLOCK_ID_LDS15                               = 0xf4,
+	DBG_BLOCK_ID_LDS16                               = 0xf5,
+	DBG_BLOCK_ID_LDS17                               = 0xf6,
+	DBG_BLOCK_ID_LDS18                               = 0xf7,
+	DBG_BLOCK_ID_LDS19                               = 0xf8,
+	DBG_BLOCK_ID_LDS1A                               = 0xf9,
+	DBG_BLOCK_ID_LDS1B                               = 0xfa,
+	DBG_BLOCK_ID_UNUSED43                            = 0xfb,
+	DBG_BLOCK_ID_UNUSED44                            = 0xfc,
+	DBG_BLOCK_ID_UNUSED45                            = 0xfd,
+	DBG_BLOCK_ID_UNUSED46                            = 0xfe,
+} DebugBlockId;
+typedef enum DebugBlockId_BY2 {
+	DBG_BLOCK_ID_RESERVED_BY2                        = 0x0,
+	DBG_BLOCK_ID_VMC_BY2                             = 0x1,
+	DBG_BLOCK_ID_UNUSED0_BY2                         = 0x2,
+	DBG_BLOCK_ID_GRBM_BY2                            = 0x3,
+	DBG_BLOCK_ID_CSC_BY2                             = 0x4,
+	DBG_BLOCK_ID_IH_BY2                              = 0x5,
+	DBG_BLOCK_ID_SQ_BY2                              = 0x6,
+	DBG_BLOCK_ID_UVD_BY2                             = 0x7,
+	DBG_BLOCK_ID_SDMA0_BY2                           = 0x8,
+	DBG_BLOCK_ID_SPIM_BY2                            = 0x9,
+	DBG_BLOCK_ID_VC0_BY2                             = 0xa,
+	DBG_BLOCK_ID_PA_BY2                              = 0xb,
+	DBG_BLOCK_ID_CP0_BY2                             = 0xc,
+	DBG_BLOCK_ID_CP2_BY2                             = 0xd,
+	DBG_BLOCK_ID_PC0_BY2                             = 0xe,
+	DBG_BLOCK_ID_BCI0_BY2                            = 0xf,
+	DBG_BLOCK_ID_SXM0_BY2                            = 0x10,
+	DBG_BLOCK_ID_SCT0_BY2                            = 0x11,
+	DBG_BLOCK_ID_SPM0_BY2                            = 0x12,
+	DBG_BLOCK_ID_BCI2_BY2                            = 0x13,
+	DBG_BLOCK_ID_TCA_BY2                             = 0x14,
+	DBG_BLOCK_ID_TCCA_BY2                            = 0x15,
+	DBG_BLOCK_ID_MCC_BY2                             = 0x16,
+	DBG_BLOCK_ID_MCC2_BY2                            = 0x17,
+	DBG_BLOCK_ID_MCD_BY2                             = 0x18,
+	DBG_BLOCK_ID_MCD2_BY2                            = 0x19,
+	DBG_BLOCK_ID_MCD4_BY2                            = 0x1a,
+	DBG_BLOCK_ID_MCB_BY2                             = 0x1b,
+	DBG_BLOCK_ID_SQA_BY2                             = 0x1c,
+	DBG_BLOCK_ID_SQA02_BY2                           = 0x1d,
+	DBG_BLOCK_ID_SQA11_BY2                           = 0x1e,
+	DBG_BLOCK_ID_UNUSED8_BY2                         = 0x1f,
+	DBG_BLOCK_ID_SQB_BY2                             = 0x20,
+	DBG_BLOCK_ID_SQB10_BY2                           = 0x21,
+	DBG_BLOCK_ID_UNUSED10_BY2                        = 0x22,
+	DBG_BLOCK_ID_UNUSED12_BY2                        = 0x23,
+	DBG_BLOCK_ID_CB_BY2                              = 0x24,
+	DBG_BLOCK_ID_CB02_BY2                            = 0x25,
+	DBG_BLOCK_ID_CB10_BY2                            = 0x26,
+	DBG_BLOCK_ID_CB12_BY2                            = 0x27,
+	DBG_BLOCK_ID_SXS_BY2                             = 0x28,
+	DBG_BLOCK_ID_SXS2_BY2                            = 0x29,
+	DBG_BLOCK_ID_SXS4_BY2                            = 0x2a,
+	DBG_BLOCK_ID_SXS6_BY2                            = 0x2b,
+	DBG_BLOCK_ID_DB_BY2                              = 0x2c,
+	DBG_BLOCK_ID_DB02_BY2                            = 0x2d,
+	DBG_BLOCK_ID_DB10_BY2                            = 0x2e,
+	DBG_BLOCK_ID_DB12_BY2                            = 0x2f,
+	DBG_BLOCK_ID_TCP_BY2                             = 0x30,
+	DBG_BLOCK_ID_TCP2_BY2                            = 0x31,
+	DBG_BLOCK_ID_TCP4_BY2                            = 0x32,
+	DBG_BLOCK_ID_TCP6_BY2                            = 0x33,
+	DBG_BLOCK_ID_TCP8_BY2                            = 0x34,
+	DBG_BLOCK_ID_TCP10_BY2                           = 0x35,
+	DBG_BLOCK_ID_TCP12_BY2                           = 0x36,
+	DBG_BLOCK_ID_TCP14_BY2                           = 0x37,
+	DBG_BLOCK_ID_TCP16_BY2                           = 0x38,
+	DBG_BLOCK_ID_TCP18_BY2                           = 0x39,
+	DBG_BLOCK_ID_TCP20_BY2                           = 0x3a,
+	DBG_BLOCK_ID_TCP22_BY2                           = 0x3b,
+	DBG_BLOCK_ID_TCP_RESERVED0_BY2                   = 0x3c,
+	DBG_BLOCK_ID_TCP_RESERVED2_BY2                   = 0x3d,
+	DBG_BLOCK_ID_TCP_RESERVED4_BY2                   = 0x3e,
+	DBG_BLOCK_ID_TCP_RESERVED6_BY2                   = 0x3f,
+	DBG_BLOCK_ID_TCC_BY2                             = 0x40,
+	DBG_BLOCK_ID_TCC2_BY2                            = 0x41,
+	DBG_BLOCK_ID_TCC4_BY2                            = 0x42,
+	DBG_BLOCK_ID_TCC6_BY2                            = 0x43,
+	DBG_BLOCK_ID_SPS_BY2                             = 0x44,
+	DBG_BLOCK_ID_SPS02_BY2                           = 0x45,
+	DBG_BLOCK_ID_SPS11_BY2                           = 0x46,
+	DBG_BLOCK_ID_UNUSED14_BY2                        = 0x47,
+	DBG_BLOCK_ID_TA_BY2                              = 0x48,
+	DBG_BLOCK_ID_TA02_BY2                            = 0x49,
+	DBG_BLOCK_ID_TA04_BY2                            = 0x4a,
+	DBG_BLOCK_ID_TA06_BY2                            = 0x4b,
+	DBG_BLOCK_ID_TA08_BY2                            = 0x4c,
+	DBG_BLOCK_ID_TA0A_BY2                            = 0x4d,
+	DBG_BLOCK_ID_UNUSED20_BY2                        = 0x4e,
+	DBG_BLOCK_ID_UNUSED22_BY2                        = 0x4f,
+	DBG_BLOCK_ID_TA10_BY2                            = 0x50,
+	DBG_BLOCK_ID_TA12_BY2                            = 0x51,
+	DBG_BLOCK_ID_TA14_BY2                            = 0x52,
+	DBG_BLOCK_ID_TA16_BY2                            = 0x53,
+	DBG_BLOCK_ID_TA18_BY2                            = 0x54,
+	DBG_BLOCK_ID_TA1A_BY2                            = 0x55,
+	DBG_BLOCK_ID_UNUSED24_BY2                        = 0x56,
+	DBG_BLOCK_ID_UNUSED26_BY2                        = 0x57,
+	DBG_BLOCK_ID_TD_BY2                              = 0x58,
+	DBG_BLOCK_ID_TD02_BY2                            = 0x59,
+	DBG_BLOCK_ID_TD04_BY2                            = 0x5a,
+	DBG_BLOCK_ID_TD06_BY2                            = 0x5b,
+	DBG_BLOCK_ID_TD08_BY2                            = 0x5c,
+	DBG_BLOCK_ID_TD0A_BY2                            = 0x5d,
+	DBG_BLOCK_ID_UNUSED28_BY2                        = 0x5e,
+	DBG_BLOCK_ID_UNUSED30_BY2                        = 0x5f,
+	DBG_BLOCK_ID_TD10_BY2                            = 0x60,
+	DBG_BLOCK_ID_TD12_BY2                            = 0x61,
+	DBG_BLOCK_ID_TD14_BY2                            = 0x62,
+	DBG_BLOCK_ID_TD16_BY2                            = 0x63,
+	DBG_BLOCK_ID_TD18_BY2                            = 0x64,
+	DBG_BLOCK_ID_TD1A_BY2                            = 0x65,
+	DBG_BLOCK_ID_UNUSED32_BY2                        = 0x66,
+	DBG_BLOCK_ID_UNUSED34_BY2                        = 0x67,
+	DBG_BLOCK_ID_LDS_BY2                             = 0x68,
+	DBG_BLOCK_ID_LDS02_BY2                           = 0x69,
+	DBG_BLOCK_ID_LDS04_BY2                           = 0x6a,
+	DBG_BLOCK_ID_LDS06_BY2                           = 0x6b,
+	DBG_BLOCK_ID_LDS08_BY2                           = 0x6c,
+	DBG_BLOCK_ID_LDS0A_BY2                           = 0x6d,
+	DBG_BLOCK_ID_UNUSED36_BY2                        = 0x6e,
+	DBG_BLOCK_ID_UNUSED38_BY2                        = 0x6f,
+	DBG_BLOCK_ID_LDS10_BY2                           = 0x70,
+	DBG_BLOCK_ID_LDS12_BY2                           = 0x71,
+	DBG_BLOCK_ID_LDS14_BY2                           = 0x72,
+	DBG_BLOCK_ID_LDS16_BY2                           = 0x73,
+	DBG_BLOCK_ID_LDS18_BY2                           = 0x74,
+	DBG_BLOCK_ID_LDS1A_BY2                           = 0x75,
+	DBG_BLOCK_ID_UNUSED40_BY2                        = 0x76,
+	DBG_BLOCK_ID_UNUSED42_BY2                        = 0x77,
+} DebugBlockId_BY2;
+typedef enum DebugBlockId_BY4 {
+	DBG_BLOCK_ID_RESERVED_BY4                        = 0x0,
+	DBG_BLOCK_ID_UNUSED0_BY4                         = 0x1,
+	DBG_BLOCK_ID_CSC_BY4                             = 0x2,
+	DBG_BLOCK_ID_SQ_BY4                              = 0x3,
+	DBG_BLOCK_ID_SDMA0_BY4                           = 0x4,
+	DBG_BLOCK_ID_VC0_BY4                             = 0x5,
+	DBG_BLOCK_ID_CP0_BY4                             = 0x6,
+	DBG_BLOCK_ID_UNUSED1_BY4                         = 0x7,
+	DBG_BLOCK_ID_SXM0_BY4                            = 0x8,
+	DBG_BLOCK_ID_SPM0_BY4                            = 0x9,
+	DBG_BLOCK_ID_TCAA_BY4                            = 0xa,
+	DBG_BLOCK_ID_MCC_BY4                             = 0xb,
+	DBG_BLOCK_ID_MCD_BY4                             = 0xc,
+	DBG_BLOCK_ID_MCD4_BY4                            = 0xd,
+	DBG_BLOCK_ID_SQA_BY4                             = 0xe,
+	DBG_BLOCK_ID_SQA11_BY4                           = 0xf,
+	DBG_BLOCK_ID_SQB_BY4                             = 0x10,
+	DBG_BLOCK_ID_UNUSED10_BY4                        = 0x11,
+	DBG_BLOCK_ID_CB_BY4                              = 0x12,
+	DBG_BLOCK_ID_CB10_BY4                            = 0x13,
+	DBG_BLOCK_ID_SXS_BY4                             = 0x14,
+	DBG_BLOCK_ID_SXS4_BY4                            = 0x15,
+	DBG_BLOCK_ID_DB_BY4                              = 0x16,
+	DBG_BLOCK_ID_DB10_BY4                            = 0x17,
+	DBG_BLOCK_ID_TCP_BY4                             = 0x18,
+	DBG_BLOCK_ID_TCP4_BY4                            = 0x19,
+	DBG_BLOCK_ID_TCP8_BY4                            = 0x1a,
+	DBG_BLOCK_ID_TCP12_BY4                           = 0x1b,
+	DBG_BLOCK_ID_TCP16_BY4                           = 0x1c,
+	DBG_BLOCK_ID_TCP20_BY4                           = 0x1d,
+	DBG_BLOCK_ID_TCP_RESERVED0_BY4                   = 0x1e,
+	DBG_BLOCK_ID_TCP_RESERVED4_BY4                   = 0x1f,
+	DBG_BLOCK_ID_TCC_BY4                             = 0x20,
+	DBG_BLOCK_ID_TCC4_BY4                            = 0x21,
+	DBG_BLOCK_ID_SPS_BY4                             = 0x22,
+	DBG_BLOCK_ID_SPS11_BY4                           = 0x23,
+	DBG_BLOCK_ID_TA_BY4                              = 0x24,
+	DBG_BLOCK_ID_TA04_BY4                            = 0x25,
+	DBG_BLOCK_ID_TA08_BY4                            = 0x26,
+	DBG_BLOCK_ID_UNUSED20_BY4                        = 0x27,
+	DBG_BLOCK_ID_TA10_BY4                            = 0x28,
+	DBG_BLOCK_ID_TA14_BY4                            = 0x29,
+	DBG_BLOCK_ID_TA18_BY4                            = 0x2a,
+	DBG_BLOCK_ID_UNUSED24_BY4                        = 0x2b,
+	DBG_BLOCK_ID_TD_BY4                              = 0x2c,
+	DBG_BLOCK_ID_TD04_BY4                            = 0x2d,
+	DBG_BLOCK_ID_TD08_BY4                            = 0x2e,
+	DBG_BLOCK_ID_UNUSED28_BY4                        = 0x2f,
+	DBG_BLOCK_ID_TD10_BY4                            = 0x30,
+	DBG_BLOCK_ID_TD14_BY4                            = 0x31,
+	DBG_BLOCK_ID_TD18_BY4                            = 0x32,
+	DBG_BLOCK_ID_UNUSED32_BY4                        = 0x33,
+	DBG_BLOCK_ID_LDS_BY4                             = 0x34,
+	DBG_BLOCK_ID_LDS04_BY4                           = 0x35,
+	DBG_BLOCK_ID_LDS08_BY4                           = 0x36,
+	DBG_BLOCK_ID_UNUSED36_BY4                        = 0x37,
+	DBG_BLOCK_ID_LDS10_BY4                           = 0x38,
+	DBG_BLOCK_ID_LDS14_BY4                           = 0x39,
+	DBG_BLOCK_ID_LDS18_BY4                           = 0x3a,
+	DBG_BLOCK_ID_UNUSED40_BY4                        = 0x3b,
+} DebugBlockId_BY4;
+typedef enum DebugBlockId_BY8 {
+	DBG_BLOCK_ID_RESERVED_BY8                        = 0x0,
+	DBG_BLOCK_ID_CSC_BY8                             = 0x1,
+	DBG_BLOCK_ID_SDMA0_BY8                           = 0x2,
+	DBG_BLOCK_ID_CP0_BY8                             = 0x3,
+	DBG_BLOCK_ID_SXM0_BY8                            = 0x4,
+	DBG_BLOCK_ID_TCA_BY8                             = 0x5,
+	DBG_BLOCK_ID_MCD_BY8                             = 0x6,
+	DBG_BLOCK_ID_SQA_BY8                             = 0x7,
+	DBG_BLOCK_ID_SQB_BY8                             = 0x8,
+	DBG_BLOCK_ID_CB_BY8                              = 0x9,
+	DBG_BLOCK_ID_SXS_BY8                             = 0xa,
+	DBG_BLOCK_ID_DB_BY8                              = 0xb,
+	DBG_BLOCK_ID_TCP_BY8                             = 0xc,
+	DBG_BLOCK_ID_TCP8_BY8                            = 0xd,
+	DBG_BLOCK_ID_TCP16_BY8                           = 0xe,
+	DBG_BLOCK_ID_TCP_RESERVED0_BY8                   = 0xf,
+	DBG_BLOCK_ID_TCC_BY8                             = 0x10,
+	DBG_BLOCK_ID_SPS_BY8                             = 0x11,
+	DBG_BLOCK_ID_TA_BY8                              = 0x12,
+	DBG_BLOCK_ID_TA08_BY8                            = 0x13,
+	DBG_BLOCK_ID_TA10_BY8                            = 0x14,
+	DBG_BLOCK_ID_TA18_BY8                            = 0x15,
+	DBG_BLOCK_ID_TD_BY8                              = 0x16,
+	DBG_BLOCK_ID_TD08_BY8                            = 0x17,
+	DBG_BLOCK_ID_TD10_BY8                            = 0x18,
+	DBG_BLOCK_ID_TD18_BY8                            = 0x19,
+	DBG_BLOCK_ID_LDS_BY8                             = 0x1a,
+	DBG_BLOCK_ID_LDS08_BY8                           = 0x1b,
+	DBG_BLOCK_ID_LDS10_BY8                           = 0x1c,
+	DBG_BLOCK_ID_LDS18_BY8                           = 0x1d,
+} DebugBlockId_BY8;
+typedef enum DebugBlockId_BY16 {
+	DBG_BLOCK_ID_RESERVED_BY16                       = 0x0,
+	DBG_BLOCK_ID_SDMA0_BY16                          = 0x1,
+	DBG_BLOCK_ID_SXM_BY16                            = 0x2,
+	DBG_BLOCK_ID_MCD_BY16                            = 0x3,
+	DBG_BLOCK_ID_SQB_BY16                            = 0x4,
+	DBG_BLOCK_ID_SXS_BY16                            = 0x5,
+	DBG_BLOCK_ID_TCP_BY16                            = 0x6,
+	DBG_BLOCK_ID_TCP16_BY16                          = 0x7,
+	DBG_BLOCK_ID_TCC_BY16                            = 0x8,
+	DBG_BLOCK_ID_TA_BY16                             = 0x9,
+	DBG_BLOCK_ID_TA10_BY16                           = 0xa,
+	DBG_BLOCK_ID_TD_BY16                             = 0xb,
+	DBG_BLOCK_ID_TD10_BY16                           = 0xc,
+	DBG_BLOCK_ID_LDS_BY16                            = 0xd,
+	DBG_BLOCK_ID_LDS10_BY16                          = 0xe,
+} DebugBlockId_BY16;
+typedef enum SurfaceEndian {
+	ENDIAN_NONE                                      = 0x0,
+	ENDIAN_8IN16                                     = 0x1,
+	ENDIAN_8IN32                                     = 0x2,
+	ENDIAN_8IN64                                     = 0x3,
+} SurfaceEndian;
+typedef enum ArrayMode {
+	ARRAY_LINEAR_GENERAL                             = 0x0,
+	ARRAY_LINEAR_ALIGNED                             = 0x1,
+	ARRAY_1D_TILED_THIN1                             = 0x2,
+	ARRAY_1D_TILED_THICK                             = 0x3,
+	ARRAY_2D_TILED_THIN1                             = 0x4,
+	ARRAY_PRT_TILED_THIN1                            = 0x5,
+	ARRAY_PRT_2D_TILED_THIN1                         = 0x6,
+	ARRAY_2D_TILED_THICK                             = 0x7,
+	ARRAY_2D_TILED_XTHICK                            = 0x8,
+	ARRAY_PRT_TILED_THICK                            = 0x9,
+	ARRAY_PRT_2D_TILED_THICK                         = 0xa,
+	ARRAY_PRT_3D_TILED_THIN1                         = 0xb,
+	ARRAY_3D_TILED_THIN1                             = 0xc,
+	ARRAY_3D_TILED_THICK                             = 0xd,
+	ARRAY_3D_TILED_XTHICK                            = 0xe,
+	ARRAY_PRT_3D_TILED_THICK                         = 0xf,
+} ArrayMode;
+typedef enum PipeTiling {
+	CONFIG_1_PIPE                                    = 0x0,
+	CONFIG_2_PIPE                                    = 0x1,
+	CONFIG_4_PIPE                                    = 0x2,
+	CONFIG_8_PIPE                                    = 0x3,
+} PipeTiling;
+typedef enum BankTiling {
+	CONFIG_4_BANK                                    = 0x0,
+	CONFIG_8_BANK                                    = 0x1,
+} BankTiling;
+typedef enum GroupInterleave {
+	CONFIG_256B_GROUP                                = 0x0,
+	CONFIG_512B_GROUP                                = 0x1,
+} GroupInterleave;
+typedef enum RowTiling {
+	CONFIG_1KB_ROW                                   = 0x0,
+	CONFIG_2KB_ROW                                   = 0x1,
+	CONFIG_4KB_ROW                                   = 0x2,
+	CONFIG_8KB_ROW                                   = 0x3,
+	CONFIG_1KB_ROW_OPT                               = 0x4,
+	CONFIG_2KB_ROW_OPT                               = 0x5,
+	CONFIG_4KB_ROW_OPT                               = 0x6,
+	CONFIG_8KB_ROW_OPT                               = 0x7,
+} RowTiling;
+typedef enum BankSwapBytes {
+	CONFIG_128B_SWAPS                                = 0x0,
+	CONFIG_256B_SWAPS                                = 0x1,
+	CONFIG_512B_SWAPS                                = 0x2,
+	CONFIG_1KB_SWAPS                                 = 0x3,
+} BankSwapBytes;
+typedef enum SampleSplitBytes {
+	CONFIG_1KB_SPLIT                                 = 0x0,
+	CONFIG_2KB_SPLIT                                 = 0x1,
+	CONFIG_4KB_SPLIT                                 = 0x2,
+	CONFIG_8KB_SPLIT                                 = 0x3,
+} SampleSplitBytes;
+typedef enum NumPipes {
+	ADDR_CONFIG_1_PIPE                               = 0x0,
+	ADDR_CONFIG_2_PIPE                               = 0x1,
+	ADDR_CONFIG_4_PIPE                               = 0x2,
+	ADDR_CONFIG_8_PIPE                               = 0x3,
+} NumPipes;
+typedef enum PipeInterleaveSize {
+	ADDR_CONFIG_PIPE_INTERLEAVE_256B                 = 0x0,
+	ADDR_CONFIG_PIPE_INTERLEAVE_512B                 = 0x1,
+} PipeInterleaveSize;
+typedef enum BankInterleaveSize {
+	ADDR_CONFIG_BANK_INTERLEAVE_1                    = 0x0,
+	ADDR_CONFIG_BANK_INTERLEAVE_2                    = 0x1,
+	ADDR_CONFIG_BANK_INTERLEAVE_4                    = 0x2,
+	ADDR_CONFIG_BANK_INTERLEAVE_8                    = 0x3,
+} BankInterleaveSize;
+typedef enum NumShaderEngines {
+	ADDR_CONFIG_1_SHADER_ENGINE                      = 0x0,
+	ADDR_CONFIG_2_SHADER_ENGINE                      = 0x1,
+} NumShaderEngines;
+typedef enum ShaderEngineTileSize {
+	ADDR_CONFIG_SE_TILE_16                           = 0x0,
+	ADDR_CONFIG_SE_TILE_32                           = 0x1,
+} ShaderEngineTileSize;
+typedef enum NumGPUs {
+	ADDR_CONFIG_1_GPU                                = 0x0,
+	ADDR_CONFIG_2_GPU                                = 0x1,
+	ADDR_CONFIG_4_GPU                                = 0x2,
+} NumGPUs;
+typedef enum MultiGPUTileSize {
+	ADDR_CONFIG_GPU_TILE_16                          = 0x0,
+	ADDR_CONFIG_GPU_TILE_32                          = 0x1,
+	ADDR_CONFIG_GPU_TILE_64                          = 0x2,
+	ADDR_CONFIG_GPU_TILE_128                         = 0x3,
+} MultiGPUTileSize;
+typedef enum RowSize {
+	ADDR_CONFIG_1KB_ROW                              = 0x0,
+	ADDR_CONFIG_2KB_ROW                              = 0x1,
+	ADDR_CONFIG_4KB_ROW                              = 0x2,
+} RowSize;
+typedef enum NumLowerPipes {
+	ADDR_CONFIG_1_LOWER_PIPES                        = 0x0,
+	ADDR_CONFIG_2_LOWER_PIPES                        = 0x1,
+} NumLowerPipes;
+typedef enum ColorTransform {
+	DCC_CT_AUTO                                      = 0x0,
+	DCC_CT_NONE                                      = 0x1,
+	ABGR_TO_A_BG_G_RB                                = 0x2,
+	BGRA_TO_BG_G_RB_A                                = 0x3,
+} ColorTransform;
+typedef enum CompareRef {
+	REF_NEVER                                        = 0x0,
+	REF_LESS                                         = 0x1,
+	REF_EQUAL                                        = 0x2,
+	REF_LEQUAL                                       = 0x3,
+	REF_GREATER                                      = 0x4,
+	REF_NOTEQUAL                                     = 0x5,
+	REF_GEQUAL                                       = 0x6,
+	REF_ALWAYS                                       = 0x7,
+} CompareRef;
+typedef enum ReadSize {
+	READ_256_BITS                                    = 0x0,
+	READ_512_BITS                                    = 0x1,
+} ReadSize;
+typedef enum DepthFormat {
+	DEPTH_INVALID                                    = 0x0,
+	DEPTH_16                                         = 0x1,
+	DEPTH_X8_24                                      = 0x2,
+	DEPTH_8_24                                       = 0x3,
+	DEPTH_X8_24_FLOAT                                = 0x4,
+	DEPTH_8_24_FLOAT                                 = 0x5,
+	DEPTH_32_FLOAT                                   = 0x6,
+	DEPTH_X24_8_32_FLOAT                             = 0x7,
+} DepthFormat;
+typedef enum ZFormat {
+	Z_INVALID                                        = 0x0,
+	Z_16                                             = 0x1,
+	Z_24                                             = 0x2,
+	Z_32_FLOAT                                       = 0x3,
+} ZFormat;
+typedef enum StencilFormat {
+	STENCIL_INVALID                                  = 0x0,
+	STENCIL_8                                        = 0x1,
+} StencilFormat;
+typedef enum CmaskMode {
+	CMASK_CLEAR_NONE                                 = 0x0,
+	CMASK_CLEAR_ONE                                  = 0x1,
+	CMASK_CLEAR_ALL                                  = 0x2,
+	CMASK_ANY_EXPANDED                               = 0x3,
+	CMASK_ALPHA0_FRAG1                               = 0x4,
+	CMASK_ALPHA0_FRAG2                               = 0x5,
+	CMASK_ALPHA0_FRAG4                               = 0x6,
+	CMASK_ALPHA0_FRAGS                               = 0x7,
+	CMASK_ALPHA1_FRAG1                               = 0x8,
+	CMASK_ALPHA1_FRAG2                               = 0x9,
+	CMASK_ALPHA1_FRAG4                               = 0xa,
+	CMASK_ALPHA1_FRAGS                               = 0xb,
+	CMASK_ALPHAX_FRAG1                               = 0xc,
+	CMASK_ALPHAX_FRAG2                               = 0xd,
+	CMASK_ALPHAX_FRAG4                               = 0xe,
+	CMASK_ALPHAX_FRAGS                               = 0xf,
+} CmaskMode;
+typedef enum QuadExportFormat {
+	EXPORT_UNUSED                                    = 0x0,
+	EXPORT_32_R                                      = 0x1,
+	EXPORT_32_GR                                     = 0x2,
+	EXPORT_32_AR                                     = 0x3,
+	EXPORT_FP16_ABGR                                 = 0x4,
+	EXPORT_UNSIGNED16_ABGR                           = 0x5,
+	EXPORT_SIGNED16_ABGR                             = 0x6,
+	EXPORT_32_ABGR                                   = 0x7,
+} QuadExportFormat;
+typedef enum QuadExportFormatOld {
+	EXPORT_4P_32BPC_ABGR                             = 0x0,
+	EXPORT_4P_16BPC_ABGR                             = 0x1,
+	EXPORT_4P_32BPC_GR                               = 0x2,
+	EXPORT_4P_32BPC_AR                               = 0x3,
+	EXPORT_2P_32BPC_ABGR                             = 0x4,
+	EXPORT_8P_32BPC_R                                = 0x5,
+} QuadExportFormatOld;
+typedef enum ColorFormat {
+	COLOR_INVALID                                    = 0x0,
+	COLOR_8                                          = 0x1,
+	COLOR_16                                         = 0x2,
+	COLOR_8_8                                        = 0x3,
+	COLOR_32                                         = 0x4,
+	COLOR_16_16                                      = 0x5,
+	COLOR_10_11_11                                   = 0x6,
+	COLOR_11_11_10                                   = 0x7,
+	COLOR_10_10_10_2                                 = 0x8,
+	COLOR_2_10_10_10                                 = 0x9,
+	COLOR_8_8_8_8                                    = 0xa,
+	COLOR_32_32                                      = 0xb,
+	COLOR_16_16_16_16                                = 0xc,
+	COLOR_RESERVED_13                                = 0xd,
+	COLOR_32_32_32_32                                = 0xe,
+	COLOR_RESERVED_15                                = 0xf,
+	COLOR_5_6_5                                      = 0x10,
+	COLOR_1_5_5_5                                    = 0x11,
+	COLOR_5_5_5_1                                    = 0x12,
+	COLOR_4_4_4_4                                    = 0x13,
+	COLOR_8_24                                       = 0x14,
+	COLOR_24_8                                       = 0x15,
+	COLOR_X24_8_32_FLOAT                             = 0x16,
+	COLOR_RESERVED_23                                = 0x17,
+} ColorFormat;
+typedef enum SurfaceFormat {
+	FMT_INVALID                                      = 0x0,
+	FMT_8                                            = 0x1,
+	FMT_16                                           = 0x2,
+	FMT_8_8                                          = 0x3,
+	FMT_32                                           = 0x4,
+	FMT_16_16                                        = 0x5,
+	FMT_10_11_11                                     = 0x6,
+	FMT_11_11_10                                     = 0x7,
+	FMT_10_10_10_2                                   = 0x8,
+	FMT_2_10_10_10                                   = 0x9,
+	FMT_8_8_8_8                                      = 0xa,
+	FMT_32_32                                        = 0xb,
+	FMT_16_16_16_16                                  = 0xc,
+	FMT_32_32_32                                     = 0xd,
+	FMT_32_32_32_32                                  = 0xe,
+	FMT_RESERVED_4                                   = 0xf,
+	FMT_5_6_5                                        = 0x10,
+	FMT_1_5_5_5                                      = 0x11,
+	FMT_5_5_5_1                                      = 0x12,
+	FMT_4_4_4_4                                      = 0x13,
+	FMT_8_24                                         = 0x14,
+	FMT_24_8                                         = 0x15,
+	FMT_X24_8_32_FLOAT                               = 0x16,
+	FMT_RESERVED_33                                  = 0x17,
+	FMT_11_11_10_FLOAT                               = 0x18,
+	FMT_16_FLOAT                                     = 0x19,
+	FMT_32_FLOAT                                     = 0x1a,
+	FMT_16_16_FLOAT                                  = 0x1b,
+	FMT_8_24_FLOAT                                   = 0x1c,
+	FMT_24_8_FLOAT                                   = 0x1d,
+	FMT_32_32_FLOAT                                  = 0x1e,
+	FMT_10_11_11_FLOAT                               = 0x1f,
+	FMT_16_16_16_16_FLOAT                            = 0x20,
+	FMT_3_3_2                                        = 0x21,
+	FMT_6_5_5                                        = 0x22,
+	FMT_32_32_32_32_FLOAT                            = 0x23,
+	FMT_RESERVED_36                                  = 0x24,
+	FMT_1                                            = 0x25,
+	FMT_1_REVERSED                                   = 0x26,
+	FMT_GB_GR                                        = 0x27,
+	FMT_BG_RG                                        = 0x28,
+	FMT_32_AS_8                                      = 0x29,
+	FMT_32_AS_8_8                                    = 0x2a,
+	FMT_5_9_9_9_SHAREDEXP                            = 0x2b,
+	FMT_8_8_8                                        = 0x2c,
+	FMT_16_16_16                                     = 0x2d,
+	FMT_16_16_16_FLOAT                               = 0x2e,
+	FMT_4_4                                          = 0x2f,
+	FMT_32_32_32_FLOAT                               = 0x30,
+	FMT_BC1                                          = 0x31,
+	FMT_BC2                                          = 0x32,
+	FMT_BC3                                          = 0x33,
+	FMT_BC4                                          = 0x34,
+	FMT_BC5                                          = 0x35,
+	FMT_BC6                                          = 0x36,
+	FMT_BC7                                          = 0x37,
+	FMT_32_AS_32_32_32_32                            = 0x38,
+	FMT_APC3                                         = 0x39,
+	FMT_APC4                                         = 0x3a,
+	FMT_APC5                                         = 0x3b,
+	FMT_APC6                                         = 0x3c,
+	FMT_APC7                                         = 0x3d,
+	FMT_CTX1                                         = 0x3e,
+	FMT_RESERVED_63                                  = 0x3f,
+} SurfaceFormat;
+typedef enum BUF_DATA_FORMAT {
+	BUF_DATA_FORMAT_INVALID                          = 0x0,
+	BUF_DATA_FORMAT_8                                = 0x1,
+	BUF_DATA_FORMAT_16                               = 0x2,
+	BUF_DATA_FORMAT_8_8                              = 0x3,
+	BUF_DATA_FORMAT_32                               = 0x4,
+	BUF_DATA_FORMAT_16_16                            = 0x5,
+	BUF_DATA_FORMAT_10_11_11                         = 0x6,
+	BUF_DATA_FORMAT_11_11_10                         = 0x7,
+	BUF_DATA_FORMAT_10_10_10_2                       = 0x8,
+	BUF_DATA_FORMAT_2_10_10_10                       = 0x9,
+	BUF_DATA_FORMAT_8_8_8_8                          = 0xa,
+	BUF_DATA_FORMAT_32_32                            = 0xb,
+	BUF_DATA_FORMAT_16_16_16_16                      = 0xc,
+	BUF_DATA_FORMAT_32_32_32                         = 0xd,
+	BUF_DATA_FORMAT_32_32_32_32                      = 0xe,
+	BUF_DATA_FORMAT_RESERVED_15                      = 0xf,
+} BUF_DATA_FORMAT;
+typedef enum IMG_DATA_FORMAT {
+	IMG_DATA_FORMAT_INVALID                          = 0x0,
+	IMG_DATA_FORMAT_8                                = 0x1,
+	IMG_DATA_FORMAT_16                               = 0x2,
+	IMG_DATA_FORMAT_8_8                              = 0x3,
+	IMG_DATA_FORMAT_32                               = 0x4,
+	IMG_DATA_FORMAT_16_16                            = 0x5,
+	IMG_DATA_FORMAT_10_11_11                         = 0x6,
+	IMG_DATA_FORMAT_11_11_10                         = 0x7,
+	IMG_DATA_FORMAT_10_10_10_2                       = 0x8,
+	IMG_DATA_FORMAT_2_10_10_10                       = 0x9,
+	IMG_DATA_FORMAT_8_8_8_8                          = 0xa,
+	IMG_DATA_FORMAT_32_32                            = 0xb,
+	IMG_DATA_FORMAT_16_16_16_16                      = 0xc,
+	IMG_DATA_FORMAT_32_32_32                         = 0xd,
+	IMG_DATA_FORMAT_32_32_32_32                      = 0xe,
+	IMG_DATA_FORMAT_RESERVED_15                      = 0xf,
+	IMG_DATA_FORMAT_5_6_5                            = 0x10,
+	IMG_DATA_FORMAT_1_5_5_5                          = 0x11,
+	IMG_DATA_FORMAT_5_5_5_1                          = 0x12,
+	IMG_DATA_FORMAT_4_4_4_4                          = 0x13,
+	IMG_DATA_FORMAT_8_24                             = 0x14,
+	IMG_DATA_FORMAT_24_8                             = 0x15,
+	IMG_DATA_FORMAT_X24_8_32                         = 0x16,
+	IMG_DATA_FORMAT_RESERVED_23                      = 0x17,
+	IMG_DATA_FORMAT_RESERVED_24                      = 0x18,
+	IMG_DATA_FORMAT_RESERVED_25                      = 0x19,
+	IMG_DATA_FORMAT_RESERVED_26                      = 0x1a,
+	IMG_DATA_FORMAT_RESERVED_27                      = 0x1b,
+	IMG_DATA_FORMAT_RESERVED_28                      = 0x1c,
+	IMG_DATA_FORMAT_RESERVED_29                      = 0x1d,
+	IMG_DATA_FORMAT_RESERVED_30                      = 0x1e,
+	IMG_DATA_FORMAT_RESERVED_31                      = 0x1f,
+	IMG_DATA_FORMAT_GB_GR                            = 0x20,
+	IMG_DATA_FORMAT_BG_RG                            = 0x21,
+	IMG_DATA_FORMAT_5_9_9_9                          = 0x22,
+	IMG_DATA_FORMAT_BC1                              = 0x23,
+	IMG_DATA_FORMAT_BC2                              = 0x24,
+	IMG_DATA_FORMAT_BC3                              = 0x25,
+	IMG_DATA_FORMAT_BC4                              = 0x26,
+	IMG_DATA_FORMAT_BC5                              = 0x27,
+	IMG_DATA_FORMAT_BC6                              = 0x28,
+	IMG_DATA_FORMAT_BC7                              = 0x29,
+	IMG_DATA_FORMAT_RESERVED_42                      = 0x2a,
+	IMG_DATA_FORMAT_RESERVED_43                      = 0x2b,
+	IMG_DATA_FORMAT_FMASK8_S2_F1                     = 0x2c,
+	IMG_DATA_FORMAT_FMASK8_S4_F1                     = 0x2d,
+	IMG_DATA_FORMAT_FMASK8_S8_F1                     = 0x2e,
+	IMG_DATA_FORMAT_FMASK8_S2_F2                     = 0x2f,
+	IMG_DATA_FORMAT_FMASK8_S4_F2                     = 0x30,
+	IMG_DATA_FORMAT_FMASK8_S4_F4                     = 0x31,
+	IMG_DATA_FORMAT_FMASK16_S16_F1                   = 0x32,
+	IMG_DATA_FORMAT_FMASK16_S8_F2                    = 0x33,
+	IMG_DATA_FORMAT_FMASK32_S16_F2                   = 0x34,
+	IMG_DATA_FORMAT_FMASK32_S8_F4                    = 0x35,
+	IMG_DATA_FORMAT_FMASK32_S8_F8                    = 0x36,
+	IMG_DATA_FORMAT_FMASK64_S16_F4                   = 0x37,
+	IMG_DATA_FORMAT_FMASK64_S16_F8                   = 0x38,
+	IMG_DATA_FORMAT_4_4                              = 0x39,
+	IMG_DATA_FORMAT_6_5_5                            = 0x3a,
+	IMG_DATA_FORMAT_1                                = 0x3b,
+	IMG_DATA_FORMAT_1_REVERSED                       = 0x3c,
+	IMG_DATA_FORMAT_32_AS_8                          = 0x3d,
+	IMG_DATA_FORMAT_32_AS_8_8                        = 0x3e,
+	IMG_DATA_FORMAT_32_AS_32_32_32_32                = 0x3f,
+} IMG_DATA_FORMAT;
+typedef enum BUF_NUM_FORMAT {
+	BUF_NUM_FORMAT_UNORM                             = 0x0,
+	BUF_NUM_FORMAT_SNORM                             = 0x1,
+	BUF_NUM_FORMAT_USCALED                           = 0x2,
+	BUF_NUM_FORMAT_SSCALED                           = 0x3,
+	BUF_NUM_FORMAT_UINT                              = 0x4,
+	BUF_NUM_FORMAT_SINT                              = 0x5,
+	BUF_NUM_FORMAT_RESERVED_6                        = 0x6,
+	BUF_NUM_FORMAT_FLOAT                             = 0x7,
+} BUF_NUM_FORMAT;
+typedef enum IMG_NUM_FORMAT {
+	IMG_NUM_FORMAT_UNORM                             = 0x0,
+	IMG_NUM_FORMAT_SNORM                             = 0x1,
+	IMG_NUM_FORMAT_USCALED                           = 0x2,
+	IMG_NUM_FORMAT_SSCALED                           = 0x3,
+	IMG_NUM_FORMAT_UINT                              = 0x4,
+	IMG_NUM_FORMAT_SINT                              = 0x5,
+	IMG_NUM_FORMAT_RESERVED_6                        = 0x6,
+	IMG_NUM_FORMAT_FLOAT                             = 0x7,
+	IMG_NUM_FORMAT_RESERVED_8                        = 0x8,
+	IMG_NUM_FORMAT_SRGB                              = 0x9,
+	IMG_NUM_FORMAT_RESERVED_10                       = 0xa,
+	IMG_NUM_FORMAT_RESERVED_11                       = 0xb,
+	IMG_NUM_FORMAT_RESERVED_12                       = 0xc,
+	IMG_NUM_FORMAT_RESERVED_13                       = 0xd,
+	IMG_NUM_FORMAT_RESERVED_14                       = 0xe,
+	IMG_NUM_FORMAT_RESERVED_15                       = 0xf,
+} IMG_NUM_FORMAT;
+typedef enum TileType {
+	ARRAY_COLOR_TILE                                 = 0x0,
+	ARRAY_DEPTH_TILE                                 = 0x1,
+} TileType;
+typedef enum NonDispTilingOrder {
+	ADDR_SURF_MICRO_TILING_DISPLAY                   = 0x0,
+	ADDR_SURF_MICRO_TILING_NON_DISPLAY               = 0x1,
+} NonDispTilingOrder;
+typedef enum MicroTileMode {
+	ADDR_SURF_DISPLAY_MICRO_TILING                   = 0x0,
+	ADDR_SURF_THIN_MICRO_TILING                      = 0x1,
+	ADDR_SURF_DEPTH_MICRO_TILING                     = 0x2,
+	ADDR_SURF_ROTATED_MICRO_TILING                   = 0x3,
+	ADDR_SURF_THICK_MICRO_TILING                     = 0x4,
+} MicroTileMode;
+typedef enum TileSplit {
+	ADDR_SURF_TILE_SPLIT_64B                         = 0x0,
+	ADDR_SURF_TILE_SPLIT_128B                        = 0x1,
+	ADDR_SURF_TILE_SPLIT_256B                        = 0x2,
+	ADDR_SURF_TILE_SPLIT_512B                        = 0x3,
+	ADDR_SURF_TILE_SPLIT_1KB                         = 0x4,
+	ADDR_SURF_TILE_SPLIT_2KB                         = 0x5,
+	ADDR_SURF_TILE_SPLIT_4KB                         = 0x6,
+} TileSplit;
+typedef enum SampleSplit {
+	ADDR_SURF_SAMPLE_SPLIT_1                         = 0x0,
+	ADDR_SURF_SAMPLE_SPLIT_2                         = 0x1,
+	ADDR_SURF_SAMPLE_SPLIT_4                         = 0x2,
+	ADDR_SURF_SAMPLE_SPLIT_8                         = 0x3,
+} SampleSplit;
+typedef enum PipeConfig {
+	ADDR_SURF_P2                                     = 0x0,
+	ADDR_SURF_P2_RESERVED0                           = 0x1,
+	ADDR_SURF_P2_RESERVED1                           = 0x2,
+	ADDR_SURF_P2_RESERVED2                           = 0x3,
+	ADDR_SURF_P4_8x16                                = 0x4,
+	ADDR_SURF_P4_16x16                               = 0x5,
+	ADDR_SURF_P4_16x32                               = 0x6,
+	ADDR_SURF_P4_32x32                               = 0x7,
+	ADDR_SURF_P8_16x16_8x16                          = 0x8,
+	ADDR_SURF_P8_16x32_8x16                          = 0x9,
+	ADDR_SURF_P8_32x32_8x16                          = 0xa,
+	ADDR_SURF_P8_16x32_16x16                         = 0xb,
+	ADDR_SURF_P8_32x32_16x16                         = 0xc,
+	ADDR_SURF_P8_32x32_16x32                         = 0xd,
+	ADDR_SURF_P8_32x64_32x32                         = 0xe,
+	ADDR_SURF_P8_RESERVED0                           = 0xf,
+	ADDR_SURF_P16_32x32_8x16                         = 0x10,
+	ADDR_SURF_P16_32x32_16x16                        = 0x11,
+} PipeConfig;
+typedef enum NumBanks {
+	ADDR_SURF_2_BANK                                 = 0x0,
+	ADDR_SURF_4_BANK                                 = 0x1,
+	ADDR_SURF_8_BANK                                 = 0x2,
+	ADDR_SURF_16_BANK                                = 0x3,
+} NumBanks;
+typedef enum BankWidth {
+	ADDR_SURF_BANK_WIDTH_1                           = 0x0,
+	ADDR_SURF_BANK_WIDTH_2                           = 0x1,
+	ADDR_SURF_BANK_WIDTH_4                           = 0x2,
+	ADDR_SURF_BANK_WIDTH_8                           = 0x3,
+} BankWidth;
+typedef enum BankHeight {
+	ADDR_SURF_BANK_HEIGHT_1                          = 0x0,
+	ADDR_SURF_BANK_HEIGHT_2                          = 0x1,
+	ADDR_SURF_BANK_HEIGHT_4                          = 0x2,
+	ADDR_SURF_BANK_HEIGHT_8                          = 0x3,
+} BankHeight;
+typedef enum BankWidthHeight {
+	ADDR_SURF_BANK_WH_1                              = 0x0,
+	ADDR_SURF_BANK_WH_2                              = 0x1,
+	ADDR_SURF_BANK_WH_4                              = 0x2,
+	ADDR_SURF_BANK_WH_8                              = 0x3,
+} BankWidthHeight;
+typedef enum MacroTileAspect {
+	ADDR_SURF_MACRO_ASPECT_1                         = 0x0,
+	ADDR_SURF_MACRO_ASPECT_2                         = 0x1,
+	ADDR_SURF_MACRO_ASPECT_4                         = 0x2,
+	ADDR_SURF_MACRO_ASPECT_8                         = 0x3,
+} MacroTileAspect;
+typedef enum GATCL1RequestType {
+	GATCL1_TYPE_NORMAL                               = 0x0,
+	GATCL1_TYPE_SHOOTDOWN                            = 0x1,
+	GATCL1_TYPE_BYPASS                               = 0x2,
+} GATCL1RequestType;
+typedef enum TCC_CACHE_POLICIES {
+	TCC_CACHE_POLICY_LRU                             = 0x0,
+	TCC_CACHE_POLICY_STREAM                          = 0x1,
+} TCC_CACHE_POLICIES;
+typedef enum MTYPE {
+	MTYPE_NC_NV                                      = 0x0,
+	MTYPE_NC                                         = 0x1,
+	MTYPE_CC                                         = 0x2,
+	MTYPE_UC                                         = 0x3,
+} MTYPE;
+typedef enum PERFMON_COUNTER_MODE {
+	PERFMON_COUNTER_MODE_ACCUM                       = 0x0,
+	PERFMON_COUNTER_MODE_ACTIVE_CYCLES               = 0x1,
+	PERFMON_COUNTER_MODE_MAX                         = 0x2,
+	PERFMON_COUNTER_MODE_DIRTY                       = 0x3,
+	PERFMON_COUNTER_MODE_SAMPLE                      = 0x4,
+	PERFMON_COUNTER_MODE_CYCLES_SINCE_FIRST_EVENT    = 0x5,
+	PERFMON_COUNTER_MODE_CYCLES_SINCE_LAST_EVENT     = 0x6,
+	PERFMON_COUNTER_MODE_CYCLES_GE_HI                = 0x7,
+	PERFMON_COUNTER_MODE_CYCLES_EQ_HI                = 0x8,
+	PERFMON_COUNTER_MODE_INACTIVE_CYCLES             = 0x9,
+	PERFMON_COUNTER_MODE_RESERVED                    = 0xf,
+} PERFMON_COUNTER_MODE;
+typedef enum PERFMON_SPM_MODE {
+	PERFMON_SPM_MODE_OFF                             = 0x0,
+	PERFMON_SPM_MODE_16BIT_CLAMP                     = 0x1,
+	PERFMON_SPM_MODE_16BIT_NO_CLAMP                  = 0x2,
+	PERFMON_SPM_MODE_32BIT_CLAMP                     = 0x3,
+	PERFMON_SPM_MODE_32BIT_NO_CLAMP                  = 0x4,
+	PERFMON_SPM_MODE_RESERVED_5                      = 0x5,
+	PERFMON_SPM_MODE_RESERVED_6                      = 0x6,
+	PERFMON_SPM_MODE_RESERVED_7                      = 0x7,
+	PERFMON_SPM_MODE_TEST_MODE_0                     = 0x8,
+	PERFMON_SPM_MODE_TEST_MODE_1                     = 0x9,
+	PERFMON_SPM_MODE_TEST_MODE_2                     = 0xa,
+} PERFMON_SPM_MODE;
+typedef enum SurfaceTiling {
+	ARRAY_LINEAR                                     = 0x0,
+	ARRAY_TILED                                      = 0x1,
+} SurfaceTiling;
+typedef enum SurfaceArray {
+	ARRAY_1D                                         = 0x0,
+	ARRAY_2D                                         = 0x1,
+	ARRAY_3D                                         = 0x2,
+	ARRAY_3D_SLICE                                   = 0x3,
+} SurfaceArray;
+typedef enum ColorArray {
+	ARRAY_2D_ALT_COLOR                               = 0x0,
+	ARRAY_2D_COLOR                                   = 0x1,
+	ARRAY_3D_SLICE_COLOR                             = 0x3,
+} ColorArray;
+typedef enum DepthArray {
+	ARRAY_2D_ALT_DEPTH                               = 0x0,
+	ARRAY_2D_DEPTH                                   = 0x1,
+} DepthArray;
+typedef enum ENUM_NUM_SIMD_PER_CU {
+	NUM_SIMD_PER_CU                                  = 0x4,
+} ENUM_NUM_SIMD_PER_CU;
+typedef enum MEM_PWR_FORCE_CTRL {
+	NO_FORCE_REQUEST                                 = 0x0,
+	FORCE_LIGHT_SLEEP_REQUEST                        = 0x1,
+	FORCE_DEEP_SLEEP_REQUEST                         = 0x2,
+	FORCE_SHUT_DOWN_REQUEST                          = 0x3,
+} MEM_PWR_FORCE_CTRL;
+typedef enum MEM_PWR_FORCE_CTRL2 {
+	NO_FORCE_REQ                                     = 0x0,
+	FORCE_LIGHT_SLEEP_REQ                            = 0x1,
+} MEM_PWR_FORCE_CTRL2;
+typedef enum MEM_PWR_DIS_CTRL {
+	ENABLE_MEM_PWR_CTRL                              = 0x0,
+	DISABLE_MEM_PWR_CTRL                             = 0x1,
+} MEM_PWR_DIS_CTRL;
+typedef enum MEM_PWR_SEL_CTRL {
+	DYNAMIC_SHUT_DOWN_ENABLE                         = 0x0,
+	DYNAMIC_DEEP_SLEEP_ENABLE                        = 0x1,
+	DYNAMIC_LIGHT_SLEEP_ENABLE                       = 0x2,
+} MEM_PWR_SEL_CTRL;
+typedef enum MEM_PWR_SEL_CTRL2 {
+	DYNAMIC_DEEP_SLEEP_EN                            = 0x0,
+	DYNAMIC_LIGHT_SLEEP_EN                           = 0x1,
+} MEM_PWR_SEL_CTRL2;
+
+#endif /* ACP_2_2_ENUM_H */
diff --git a/sound/soc/amd/include/acp_2_2_sh_mask.h b/sound/soc/amd/include/acp_2_2_sh_mask.h
new file mode 100644
index 0000000..32d2d41
--- /dev/null
+++ b/sound/soc/amd/include/acp_2_2_sh_mask.h
@@ -0,0 +1,2292 @@
+/*
+ * ACP_2_2 Register documentation
+ *
+ * Copyright (C) 2014  Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef ACP_2_2_SH_MASK_H
+#define ACP_2_2_SH_MASK_H
+
+#define ACP_DMA_CNTL_0__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_0__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_0__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_0__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_0__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_0__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_0__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_0__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_0__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_0__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_1__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_1__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_1__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_1__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_1__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_1__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_1__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_1__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_1__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_1__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_2__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_2__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_2__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_2__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_2__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_2__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_2__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_2__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_2__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_2__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_3__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_3__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_3__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_3__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_3__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_3__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_3__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_3__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_3__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_3__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_4__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_4__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_4__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_4__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_4__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_4__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_4__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_4__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_4__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_4__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_5__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_5__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_5__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_5__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_5__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_5__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_5__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_5__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_5__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_5__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_6__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_6__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_6__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_6__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_6__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_6__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_6__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_6__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_6__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_6__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_7__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_7__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_7__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_7__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_7__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_7__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_7__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_7__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_7__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_7__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_8__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_8__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_8__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_8__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_8__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_8__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_8__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_8__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_8__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_8__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_9__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_9__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_9__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_9__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_9__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_9__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_9__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_9__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_9__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_9__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_10__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_10__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_10__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_10__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_10__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_10__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_10__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_10__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_10__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_10__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_11__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_11__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_11__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_11__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_11__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_11__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_11__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_11__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_11__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_11__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_12__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_12__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_12__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_12__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_12__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_12__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_12__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_12__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_12__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_12__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_13__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_13__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_13__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_13__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_13__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_13__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_13__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_13__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_13__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_13__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_14__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_14__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_14__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_14__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_14__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_14__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_14__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_14__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_14__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_14__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_CNTL_15__DMAChRst_MASK 0x1
+#define ACP_DMA_CNTL_15__DMAChRst__SHIFT 0x0
+#define ACP_DMA_CNTL_15__DMAChRun_MASK 0x2
+#define ACP_DMA_CNTL_15__DMAChRun__SHIFT 0x1
+#define ACP_DMA_CNTL_15__DMAChIOCEn_MASK 0x4
+#define ACP_DMA_CNTL_15__DMAChIOCEn__SHIFT 0x2
+#define ACP_DMA_CNTL_15__Circular_DMA_En_MASK 0x8
+#define ACP_DMA_CNTL_15__Circular_DMA_En__SHIFT 0x3
+#define ACP_DMA_CNTL_15__DMAChGracefulRstEn_MASK 0x10
+#define ACP_DMA_CNTL_15__DMAChGracefulRstEn__SHIFT 0x4
+#define ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_1__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_1__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_2__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_2__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_3__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_3__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_4__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_4__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_5__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_5__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_6__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_6__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_7__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_7__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_8__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_8__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_9__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_9__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_10__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_10__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_11__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_11__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_12__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_12__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_13__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_13__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_14__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_14__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_STRT_IDX_15__DMAChDscrStrtIdx_MASK 0x3ff
+#define ACP_DMA_DSCR_STRT_IDX_15__DMAChDscrStrtIdx__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_0__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_0__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_1__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_1__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_2__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_2__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_3__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_3__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_4__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_4__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_5__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_5__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_6__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_6__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_7__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_7__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_8__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_8__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_9__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_9__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_10__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_10__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_11__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_11__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_12__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_12__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_13__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_13__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_14__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_14__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_DSCR_CNT_15__DMAChDscrCnt_MASK 0x3ff
+#define ACP_DMA_DSCR_CNT_15__DMAChDscrCnt__SHIFT 0x0
+#define ACP_DMA_PRIO_0__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_0__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_1__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_1__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_2__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_2__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_3__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_3__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_4__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_4__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_5__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_5__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_6__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_6__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_7__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_7__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_8__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_8__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_9__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_9__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_10__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_10__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_11__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_11__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_12__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_12__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_13__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_13__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_14__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_14__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_PRIO_15__DMAChPrioLvl_MASK 0x1
+#define ACP_DMA_PRIO_15__DMAChPrioLvl__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_0__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_0__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_1__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_1__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_2__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_2__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_3__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_3__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_4__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_4__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_5__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_5__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_6__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_6__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_7__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_7__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_8__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_8__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_9__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_9__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_10__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_10__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_11__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_11__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_12__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_12__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_13__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_13__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_14__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_14__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_DSCR_15__DMAChCurDscrIdx_MASK 0x3ff
+#define ACP_DMA_CUR_DSCR_15__DMAChCurDscrIdx__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_0__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_0__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_1__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_1__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_2__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_2__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_3__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_3__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_4__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_4__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_5__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_5__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_6__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_6__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_7__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_7__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_8__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_8__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_9__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_9__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_10__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_10__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_11__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_11__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_12__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_12__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_13__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_13__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_14__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_14__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_CUR_TRANS_CNT_15__DMAChCurTransCnt_MASK 0x1ffff
+#define ACP_DMA_CUR_TRANS_CNT_15__DMAChCurTransCnt__SHIFT 0x0
+#define ACP_DMA_ERR_STS_0__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_0__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_0__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_0__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_1__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_1__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_1__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_1__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_2__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_2__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_2__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_2__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_3__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_3__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_3__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_3__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_4__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_4__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_4__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_4__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_5__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_5__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_5__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_5__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_6__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_6__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_6__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_6__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_7__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_7__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_7__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_7__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_8__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_8__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_8__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_8__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_9__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_9__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_9__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_9__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_10__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_10__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_10__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_10__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_11__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_11__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_11__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_11__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_12__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_12__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_12__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_12__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_13__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_13__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_13__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_13__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_14__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_14__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_14__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_14__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_ERR_STS_15__DMAChTermErr_MASK 0x1
+#define ACP_DMA_ERR_STS_15__DMAChTermErr__SHIFT 0x0
+#define ACP_DMA_ERR_STS_15__DMAChErrCode_MASK 0x1e
+#define ACP_DMA_ERR_STS_15__DMAChErrCode__SHIFT 0x1
+#define ACP_DMA_DESC_BASE_ADDR__DescriptorBaseAddr_MASK 0xffffffff
+#define ACP_DMA_DESC_BASE_ADDR__DescriptorBaseAddr__SHIFT 0x0
+#define ACP_DMA_DESC_MAX_NUM_DSCR__MaximumNumberDescr_MASK 0xf
+#define ACP_DMA_DESC_MAX_NUM_DSCR__MaximumNumberDescr__SHIFT 0x0
+#define ACP_DMA_CH_STS__DMAChSts_MASK 0xffff
+#define ACP_DMA_CH_STS__DMAChSts__SHIFT 0x0
+#define ACP_DMA_CH_GROUP__DMAChanelGrouping_MASK 0x1
+#define ACP_DMA_CH_GROUP__DMAChanelGrouping__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET2__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET2__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET2__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET2__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE2__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE2__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE2__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE2__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET3__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET3__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET3__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET3__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE3__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE3__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE3__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE3__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET4__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET4__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET4__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET4__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE4__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE4__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE4__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE4__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET5__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET5__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET5__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET5__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE5__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE5__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE5__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE5__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET6__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET6__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET6__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET6__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE6__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE6__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE6__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE6__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET7__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET7__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET7__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET7__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE7__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE7__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE7__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE7__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_CACHE_OFFSET8__Offset_MASK 0xfffffff
+#define ACP_DSP0_CACHE_OFFSET8__Offset__SHIFT 0x0
+#define ACP_DSP0_CACHE_OFFSET8__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_CACHE_OFFSET8__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_CACHE_SIZE8__Size_MASK 0xffffff
+#define ACP_DSP0_CACHE_SIZE8__Size__SHIFT 0x0
+#define ACP_DSP0_CACHE_SIZE8__PageEnable_MASK 0x80000000
+#define ACP_DSP0_CACHE_SIZE8__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_NONCACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP0_NONCACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP0_NONCACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_NONCACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_NONCACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP0_NONCACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP0_NONCACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP0_NONCACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_NONCACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP0_NONCACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP0_NONCACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP0_NONCACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP0_NONCACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP0_NONCACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP0_NONCACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP0_NONCACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP0_DEBUG_PC__DebugPC_MASK 0xffffffff
+#define ACP_DSP0_DEBUG_PC__DebugPC__SHIFT 0x0
+#define ACP_DSP0_NMI_SEL__NMISel_MASK 0x1
+#define ACP_DSP0_NMI_SEL__NMISel__SHIFT 0x0
+#define ACP_DSP0_CLKRST_CNTL__ClkEn_MASK 0x1
+#define ACP_DSP0_CLKRST_CNTL__ClkEn__SHIFT 0x0
+#define ACP_DSP0_CLKRST_CNTL__SoftResetDSP_MASK 0x2
+#define ACP_DSP0_CLKRST_CNTL__SoftResetDSP__SHIFT 0x1
+#define ACP_DSP0_CLKRST_CNTL__InternalSoftResetMode_MASK 0x4
+#define ACP_DSP0_CLKRST_CNTL__InternalSoftResetMode__SHIFT 0x2
+#define ACP_DSP0_CLKRST_CNTL__ExternalSoftResetMode_MASK 0x8
+#define ACP_DSP0_CLKRST_CNTL__ExternalSoftResetMode__SHIFT 0x3
+#define ACP_DSP0_CLKRST_CNTL__SoftResetDSPDone_MASK 0x10
+#define ACP_DSP0_CLKRST_CNTL__SoftResetDSPDone__SHIFT 0x4
+#define ACP_DSP0_CLKRST_CNTL__Clk_ON_Status_MASK 0x20
+#define ACP_DSP0_CLKRST_CNTL__Clk_ON_Status__SHIFT 0x5
+#define ACP_DSP0_RUNSTALL__RunStallCntl_MASK 0x1
+#define ACP_DSP0_RUNSTALL__RunStallCntl__SHIFT 0x0
+#define ACP_DSP0_OCD_HALT_ON_RST__OCD_HALT_ON_RST_MASK 0x1
+#define ACP_DSP0_OCD_HALT_ON_RST__OCD_HALT_ON_RST__SHIFT 0x0
+#define ACP_DSP0_WAIT_MODE__WaitMode_MASK 0x1
+#define ACP_DSP0_WAIT_MODE__WaitMode__SHIFT 0x0
+#define ACP_DSP0_VECT_SEL__StaticVectorSel_MASK 0x1
+#define ACP_DSP0_VECT_SEL__StaticVectorSel__SHIFT 0x0
+#define ACP_DSP0_DEBUG_REG1__ACP_DSP_DEBUG_REG1_MASK 0xffffffff
+#define ACP_DSP0_DEBUG_REG1__ACP_DSP_DEBUG_REG1__SHIFT 0x0
+#define ACP_DSP0_DEBUG_REG2__ACP_DSP_DEBUG_REG2_MASK 0xffffffff
+#define ACP_DSP0_DEBUG_REG2__ACP_DSP_DEBUG_REG2__SHIFT 0x0
+#define ACP_DSP0_DEBUG_REG3__ACP_DSP_DEBUG_REG3_MASK 0xffffffff
+#define ACP_DSP0_DEBUG_REG3__ACP_DSP_DEBUG_REG3__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET2__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET2__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET2__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET2__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE2__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE2__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE2__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE2__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET3__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET3__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET3__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET3__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE3__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE3__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE3__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE3__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET4__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET4__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET4__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET4__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE4__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE4__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE4__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE4__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET5__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET5__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET5__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET5__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE5__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE5__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE5__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE5__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET6__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET6__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET6__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET6__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE6__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE6__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE6__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE6__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET7__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET7__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET7__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET7__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE7__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE7__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE7__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE7__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_CACHE_OFFSET8__Offset_MASK 0xfffffff
+#define ACP_DSP1_CACHE_OFFSET8__Offset__SHIFT 0x0
+#define ACP_DSP1_CACHE_OFFSET8__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_CACHE_OFFSET8__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_CACHE_SIZE8__Size_MASK 0xffffff
+#define ACP_DSP1_CACHE_SIZE8__Size__SHIFT 0x0
+#define ACP_DSP1_CACHE_SIZE8__PageEnable_MASK 0x80000000
+#define ACP_DSP1_CACHE_SIZE8__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_NONCACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP1_NONCACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP1_NONCACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_NONCACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_NONCACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP1_NONCACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP1_NONCACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP1_NONCACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_NONCACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP1_NONCACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP1_NONCACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP1_NONCACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP1_NONCACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP1_NONCACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP1_NONCACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP1_NONCACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP1_DEBUG_PC__DebugPC_MASK 0xffffffff
+#define ACP_DSP1_DEBUG_PC__DebugPC__SHIFT 0x0
+#define ACP_DSP1_NMI_SEL__NMISel_MASK 0x1
+#define ACP_DSP1_NMI_SEL__NMISel__SHIFT 0x0
+#define ACP_DSP1_CLKRST_CNTL__ClkEn_MASK 0x1
+#define ACP_DSP1_CLKRST_CNTL__ClkEn__SHIFT 0x0
+#define ACP_DSP1_CLKRST_CNTL__SoftResetDSP_MASK 0x2
+#define ACP_DSP1_CLKRST_CNTL__SoftResetDSP__SHIFT 0x1
+#define ACP_DSP1_CLKRST_CNTL__InternalSoftResetMode_MASK 0x4
+#define ACP_DSP1_CLKRST_CNTL__InternalSoftResetMode__SHIFT 0x2
+#define ACP_DSP1_CLKRST_CNTL__ExternalSoftResetMode_MASK 0x8
+#define ACP_DSP1_CLKRST_CNTL__ExternalSoftResetMode__SHIFT 0x3
+#define ACP_DSP1_CLKRST_CNTL__SoftResetDSPDone_MASK 0x10
+#define ACP_DSP1_CLKRST_CNTL__SoftResetDSPDone__SHIFT 0x4
+#define ACP_DSP1_CLKRST_CNTL__Clk_ON_Status_MASK 0x20
+#define ACP_DSP1_CLKRST_CNTL__Clk_ON_Status__SHIFT 0x5
+#define ACP_DSP1_RUNSTALL__RunStallCntl_MASK 0x1
+#define ACP_DSP1_RUNSTALL__RunStallCntl__SHIFT 0x0
+#define ACP_DSP1_OCD_HALT_ON_RST__OCD_HALT_ON_RST_MASK 0x1
+#define ACP_DSP1_OCD_HALT_ON_RST__OCD_HALT_ON_RST__SHIFT 0x0
+#define ACP_DSP1_WAIT_MODE__WaitMode_MASK 0x1
+#define ACP_DSP1_WAIT_MODE__WaitMode__SHIFT 0x0
+#define ACP_DSP1_VECT_SEL__StaticVectorSel_MASK 0x1
+#define ACP_DSP1_VECT_SEL__StaticVectorSel__SHIFT 0x0
+#define ACP_DSP1_DEBUG_REG1__ACP_DSP_DEBUG_REG1_MASK 0xffffffff
+#define ACP_DSP1_DEBUG_REG1__ACP_DSP_DEBUG_REG1__SHIFT 0x0
+#define ACP_DSP1_DEBUG_REG2__ACP_DSP_DEBUG_REG2_MASK 0xffffffff
+#define ACP_DSP1_DEBUG_REG2__ACP_DSP_DEBUG_REG2__SHIFT 0x0
+#define ACP_DSP1_DEBUG_REG3__ACP_DSP_DEBUG_REG3_MASK 0xffffffff
+#define ACP_DSP1_DEBUG_REG3__ACP_DSP_DEBUG_REG3__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET2__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET2__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET2__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET2__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE2__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE2__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE2__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE2__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET3__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET3__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET3__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET3__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE3__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE3__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE3__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE3__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET4__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET4__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET4__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET4__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE4__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE4__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE4__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE4__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET5__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET5__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET5__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET5__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE5__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE5__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE5__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE5__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET6__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET6__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET6__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET6__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE6__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE6__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE6__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE6__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET7__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET7__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET7__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET7__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE7__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE7__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE7__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE7__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_CACHE_OFFSET8__Offset_MASK 0xfffffff
+#define ACP_DSP2_CACHE_OFFSET8__Offset__SHIFT 0x0
+#define ACP_DSP2_CACHE_OFFSET8__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_CACHE_OFFSET8__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_CACHE_SIZE8__Size_MASK 0xffffff
+#define ACP_DSP2_CACHE_SIZE8__Size__SHIFT 0x0
+#define ACP_DSP2_CACHE_SIZE8__PageEnable_MASK 0x80000000
+#define ACP_DSP2_CACHE_SIZE8__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_NONCACHE_OFFSET0__Offset_MASK 0xfffffff
+#define ACP_DSP2_NONCACHE_OFFSET0__Offset__SHIFT 0x0
+#define ACP_DSP2_NONCACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_NONCACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_NONCACHE_SIZE0__Size_MASK 0xffffff
+#define ACP_DSP2_NONCACHE_SIZE0__Size__SHIFT 0x0
+#define ACP_DSP2_NONCACHE_SIZE0__PageEnable_MASK 0x80000000
+#define ACP_DSP2_NONCACHE_SIZE0__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_NONCACHE_OFFSET1__Offset_MASK 0xfffffff
+#define ACP_DSP2_NONCACHE_OFFSET1__Offset__SHIFT 0x0
+#define ACP_DSP2_NONCACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000
+#define ACP_DSP2_NONCACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f
+#define ACP_DSP2_NONCACHE_SIZE1__Size_MASK 0xffffff
+#define ACP_DSP2_NONCACHE_SIZE1__Size__SHIFT 0x0
+#define ACP_DSP2_NONCACHE_SIZE1__PageEnable_MASK 0x80000000
+#define ACP_DSP2_NONCACHE_SIZE1__PageEnable__SHIFT 0x1f
+#define ACP_DSP2_DEBUG_PC__DebugPC_MASK 0xffffffff
+#define ACP_DSP2_DEBUG_PC__DebugPC__SHIFT 0x0
+#define ACP_DSP2_NMI_SEL__NMISel_MASK 0x1
+#define ACP_DSP2_NMI_SEL__NMISel__SHIFT 0x0
+#define ACP_DSP2_CLKRST_CNTL__ClkEn_MASK 0x1
+#define ACP_DSP2_CLKRST_CNTL__ClkEn__SHIFT 0x0
+#define ACP_DSP2_CLKRST_CNTL__SoftResetDSP_MASK 0x2
+#define ACP_DSP2_CLKRST_CNTL__SoftResetDSP__SHIFT 0x1
+#define ACP_DSP2_CLKRST_CNTL__InternalSoftResetMode_MASK 0x4
+#define ACP_DSP2_CLKRST_CNTL__InternalSoftResetMode__SHIFT 0x2
+#define ACP_DSP2_CLKRST_CNTL__ExternalSoftResetMode_MASK 0x8
+#define ACP_DSP2_CLKRST_CNTL__ExternalSoftResetMode__SHIFT 0x3
+#define ACP_DSP2_CLKRST_CNTL__SoftResetDSPDone_MASK 0x10
+#define ACP_DSP2_CLKRST_CNTL__SoftResetDSPDone__SHIFT 0x4
+#define ACP_DSP2_CLKRST_CNTL__Clk_ON_Status_MASK 0x20
+#define ACP_DSP2_CLKRST_CNTL__Clk_ON_Status__SHIFT 0x5
+#define ACP_DSP2_RUNSTALL__RunStallCntl_MASK 0x1
+#define ACP_DSP2_RUNSTALL__RunStallCntl__SHIFT 0x0
+#define ACP_DSP2_OCD_HALT_ON_RST__OCD_HALT_ON_RST_MASK 0x1
+#define ACP_DSP2_OCD_HALT_ON_RST__OCD_HALT_ON_RST__SHIFT 0x0
+#define ACP_DSP2_WAIT_MODE__WaitMode_MASK 0x1
+#define ACP_DSP2_WAIT_MODE__WaitMode__SHIFT 0x0
+#define ACP_DSP2_VECT_SEL__StaticVectorSel_MASK 0x1
+#define ACP_DSP2_VECT_SEL__StaticVectorSel__SHIFT 0x0
+#define ACP_DSP2_DEBUG_REG1__ACP_DSP_DEBUG_REG1_MASK 0xffffffff
+#define ACP_DSP2_DEBUG_REG1__ACP_DSP_DEBUG_REG1__SHIFT 0x0
+#define ACP_DSP2_DEBUG_REG2__ACP_DSP_DEBUG_REG2_MASK 0xffffffff
+#define ACP_DSP2_DEBUG_REG2__ACP_DSP_DEBUG_REG2__SHIFT 0x0
+#define ACP_DSP2_DEBUG_REG3__ACP_DSP_DEBUG_REG3_MASK 0xffffffff
+#define ACP_DSP2_DEBUG_REG3__ACP_DSP_DEBUG_REG3__SHIFT 0x0
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBDataSwap_MASK 0x3
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBDataSwap__SHIFT 0x0
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultRdReq_MASK 0x4
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultRdReq__SHIFT 0x2
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultWrReq_MASK 0x18
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultWrReq__SHIFT 0x3
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBMaxReadBurst_MASK 0x60
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBMaxReadBurst__SHIFT 0x5
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallEnb_MASK 0x80
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallEnb__SHIFT 0x7
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBNackChkEnb_MASK 0x100
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBNackChkEnb__SHIFT 0x8
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBAdrWinViolChkEnb_MASK 0x200
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBAdrWinViolChkEnb__SHIFT 0x9
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgEnb_MASK 0x400
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgEnb__SHIFT 0xa
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgCntMult_MASK 0x1800
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgCntMult__SHIFT 0xb
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallMode_MASK 0x2000
+#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallMode__SHIFT 0xd
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver_MASK 0x2000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver__SHIFT 0x19
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource_MASK 0x1c000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource__SHIFT 0x1a
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViol_MASK 0x20000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViol__SHIFT 0x1d
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackOver_MASK 0x40000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackOver__SHIFT 0x1e
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackVal_MASK 0x80000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackVal__SHIFT 0x1f
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver_MASK 0x2000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver__SHIFT 0x19
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource_MASK 0x1c000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource__SHIFT 0x1a
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViol_MASK 0x20000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViol__SHIFT 0x1d
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackOver_MASK 0x40000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackOver__SHIFT 0x1e
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackVal_MASK 0x80000000
+#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackVal__SHIFT 0x1f
+#define ACP_DAGB_Onion_TransPerf_Counter_Control__EnbDAGBTransPerfCntr_MASK 0x1
+#define ACP_DAGB_Onion_TransPerf_Counter_Control__EnbDAGBTransPerfCntr__SHIFT 0x0
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBDataSwap_MASK 0x3
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBDataSwap__SHIFT 0x0
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultRdReq_MASK 0x4
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultRdReq__SHIFT 0x2
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultWrReq_MASK 0x18
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultWrReq__SHIFT 0x3
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBMaxReadBurst_MASK 0x60
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBMaxReadBurst__SHIFT 0x5
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallEnb_MASK 0x80
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallEnb__SHIFT 0x7
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBNackChkEnb_MASK 0x100
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBNackChkEnb__SHIFT 0x8
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBAdrWinViolChkEnb_MASK 0x200
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBAdrWinViolChkEnb__SHIFT 0x9
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgEnb_MASK 0x400
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgEnb__SHIFT 0xa
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgCntMult_MASK 0x1800
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgCntMult__SHIFT 0xb
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallMode_MASK 0x2000
+#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallMode__SHIFT 0xd
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver_MASK 0x2000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver__SHIFT 0x19
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource_MASK 0x1c000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource__SHIFT 0x1a
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViol_MASK 0x20000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViol__SHIFT 0x1d
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackOver_MASK 0x40000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackOver__SHIFT 0x1e
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackVal_MASK 0x80000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackVal__SHIFT 0x1f
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver_MASK 0x2000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver__SHIFT 0x19
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource_MASK 0x1c000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource__SHIFT 0x1a
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViol_MASK 0x20000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViol__SHIFT 0x1d
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackOver_MASK 0x40000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackOver__SHIFT 0x1e
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackVal_MASK 0x80000000
+#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackVal__SHIFT 0x1f
+#define ACP_DAGB_Garlic_TransPerf_Counter_Control__EnbDAGBTransPerfCntr_MASK 0x1
+#define ACP_DAGB_Garlic_TransPerf_Counter_Control__EnbDAGBTransPerfCntr__SHIFT 0x0
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000
+#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_1__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_1__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_2__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_2__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_3__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_3__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_4__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_4__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_5__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_5__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_6__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_6__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_7__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_7__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_PAGE_SIZE_GRP_8__AXI2DAGBPageSize_MASK 0x3
+#define ACP_DAGB_PAGE_SIZE_GRP_8__AXI2DAGBPageSize__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBBaseAddr_MASK 0xfffffff
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBBaseAddr__SHIFT 0x0
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBSnoopSel_MASK 0x20000000
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBSnoopSel__SHIFT 0x1d
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBTargetMemSel_MASK 0x40000000
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBTargetMemSel__SHIFT 0x1e
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBGrpEnable_MASK 0x80000000
+#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBGrpEnable__SHIFT 0x1f
+#define ACP_DAGB_ATU_CTRL__AXI2DAGBCacheInvalidate_MASK 0x1
+#define ACP_DAGB_ATU_CTRL__AXI2DAGBCacheInvalidate__SHIFT 0x0
+#define ACP_CONTROL__ClkEn_MASK 0x1
+#define ACP_CONTROL__ClkEn__SHIFT 0x0
+#define ACP_CONTROL__JtagEn_MASK 0x400
+#define ACP_CONTROL__JtagEn__SHIFT 0xa
+#define ACP_STATUS__ClkOn_MASK 0x1
+#define ACP_STATUS__ClkOn__SHIFT 0x0
+#define ACP_STATUS__ACPRefClkSpd_MASK 0x2
+#define ACP_STATUS__ACPRefClkSpd__SHIFT 0x1
+#define ACP_STATUS__SMUStutterLastEdge_MASK 0x4
+#define ACP_STATUS__SMUStutterLastEdge__SHIFT 0x2
+#define ACP_STATUS__MCStutterLastEdge_MASK 0x8
+#define ACP_STATUS__MCStutterLastEdge__SHIFT 0x3
+#define ACP_SOFT_RESET__SoftResetAud_MASK 0x100
+#define ACP_SOFT_RESET__SoftResetAud__SHIFT 0x8
+#define ACP_SOFT_RESET__SoftResetDMA_MASK 0x200
+#define ACP_SOFT_RESET__SoftResetDMA__SHIFT 0x9
+#define ACP_SOFT_RESET__InternalSoftResetMode_MASK 0x4000
+#define ACP_SOFT_RESET__InternalSoftResetMode__SHIFT 0xe
+#define ACP_SOFT_RESET__ExternalSoftResetMode_MASK 0x8000
+#define ACP_SOFT_RESET__ExternalSoftResetMode__SHIFT 0xf
+#define ACP_SOFT_RESET__SoftResetAudDone_MASK 0x1000000
+#define ACP_SOFT_RESET__SoftResetAudDone__SHIFT 0x18
+#define ACP_SOFT_RESET__SoftResetDMADone_MASK 0x2000000
+#define ACP_SOFT_RESET__SoftResetDMADone__SHIFT 0x19
+#define ACP_PwrMgmt_CNTL__SCLKSleepCntl_MASK 0x3
+#define ACP_PwrMgmt_CNTL__SCLKSleepCntl__SHIFT 0x0
+#define ACP_CAC_INDICATOR_CONTROL__ACP_Cac_Indicator_Counter_MASK 0xffff
+#define ACP_CAC_INDICATOR_CONTROL__ACP_Cac_Indicator_Counter__SHIFT 0x0
+#define ACP_SMU_MAILBOX__ACP_SMU_Mailbox_MASK 0xffffffff
+#define ACP_SMU_MAILBOX__ACP_SMU_Mailbox__SHIFT 0x0
+#define ACP_FUTURE_REG_SCLK_0__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_SCLK_0__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_SCLK_1__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_SCLK_1__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_SCLK_2__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_SCLK_2__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_SCLK_3__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_SCLK_3__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_SCLK_4__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_SCLK_4__ACPFutureReg__SHIFT 0x0
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_ask_cnt_enable_MASK 0x1
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_ask_cnt_enable__SHIFT 0x0
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_go_cnt_enable_MASK 0x2
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_go_cnt_enable__SHIFT 0x1
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_exp_respcnt_enable_MASK 0x4
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_exp_respcnt_enable__SHIFT 0x2
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_actual_respcnt_enable_MASK 0x8
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_actual_respcnt_enable__SHIFT 0x3
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_ask_cnt_enable_MASK 0x10
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_ask_cnt_enable__SHIFT 0x4
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_go_cnt_enable_MASK 0x20
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_go_cnt_enable__SHIFT 0x5
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_exp_respcnt_enable_MASK 0x40
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_exp_respcnt_enable__SHIFT 0x6
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_actual_respcnt_enable_MASK 0x80
+#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_actual_respcnt_enable__SHIFT 0x7
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_ask_cnt_enable_MASK 0x100
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_ask_cnt_enable__SHIFT 0x8
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_go_cnt_enable_MASK 0x200
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_go_cnt_enable__SHIFT 0x9
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_exp_respcnt_enable_MASK 0x400
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_exp_respcnt_enable__SHIFT 0xa
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_actual_respcnt_enable_MASK 0x800
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_actual_respcnt_enable__SHIFT 0xb
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_ask_cnt_enable_MASK 0x1000
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_ask_cnt_enable__SHIFT 0xc
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_go_cnt_enable_MASK 0x2000
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_go_cnt_enable__SHIFT 0xd
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_exp_respcnt_enable_MASK 0x4000
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_exp_respcnt_enable__SHIFT 0xe
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_actual_respcnt_enable_MASK 0x8000
+#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_actual_respcnt_enable__SHIFT 0xf
+#define ACP_DAGBG_WR_ASK_CNT__garlic_wr_only_ask_cnt_MASK 0xffff
+#define ACP_DAGBG_WR_ASK_CNT__garlic_wr_only_ask_cnt__SHIFT 0x0
+#define ACP_DAGBG_WR_GO_CNT__garlic_wr_only_go_cnt_MASK 0xffff
+#define ACP_DAGBG_WR_GO_CNT__garlic_wr_only_go_cnt__SHIFT 0x0
+#define ACP_DAGBG_WR_EXP_RESP_CNT__garlic_wr_exp_resp_cnt_MASK 0xffff
+#define ACP_DAGBG_WR_EXP_RESP_CNT__garlic_wr_exp_resp_cnt__SHIFT 0x0
+#define ACP_DAGBG_WR_ACTUAL_RESP_CNT__garlic_wr_actual_resp_cnt_MASK 0xffff
+#define ACP_DAGBG_WR_ACTUAL_RESP_CNT__garlic_wr_actual_resp_cnt__SHIFT 0x0
+#define ACP_DAGBG_RD_ASK_CNT__garlic_rd_only_ask_cnt_MASK 0xffff
+#define ACP_DAGBG_RD_ASK_CNT__garlic_rd_only_ask_cnt__SHIFT 0x0
+#define ACP_DAGBG_RD_GO_CNT__garlic_rd_only_go_cnt_MASK 0xffff
+#define ACP_DAGBG_RD_GO_CNT__garlic_rd_only_go_cnt__SHIFT 0x0
+#define ACP_DAGBG_RD_EXP_RESP_CNT__garlic_rd_exp_resp_cnt_MASK 0xffff
+#define ACP_DAGBG_RD_EXP_RESP_CNT__garlic_rd_exp_resp_cnt__SHIFT 0x0
+#define ACP_DAGBG_RD_ACTUAL_RESP_CNT__garlic_rd_actual_resp_cnt_MASK 0xffff
+#define ACP_DAGBG_RD_ACTUAL_RESP_CNT__garlic_rd_actual_resp_cnt__SHIFT 0x0
+#define ACP_DAGBO_WR_ASK_CNT__onion_wr_only_ask_cnt_MASK 0xffff
+#define ACP_DAGBO_WR_ASK_CNT__onion_wr_only_ask_cnt__SHIFT 0x0
+#define ACP_DAGBO_WR_GO_CNT__onion_wr_only_go_cnt_MASK 0xffff
+#define ACP_DAGBO_WR_GO_CNT__onion_wr_only_go_cnt__SHIFT 0x0
+#define ACP_DAGBO_WR_EXP_RESP_CNT__onion_wr_exp_resp_cnt_MASK 0xffff
+#define ACP_DAGBO_WR_EXP_RESP_CNT__onion_wr_exp_resp_cnt__SHIFT 0x0
+#define ACP_DAGBO_WR_ACTUAL_RESP_CNT__onion_wr_actual_resp_cnt_MASK 0xffff
+#define ACP_DAGBO_WR_ACTUAL_RESP_CNT__onion_wr_actual_resp_cnt__SHIFT 0x0
+#define ACP_DAGBO_RD_ASK_CNT__onion_rd_only_ask_cnt_MASK 0xffff
+#define ACP_DAGBO_RD_ASK_CNT__onion_rd_only_ask_cnt__SHIFT 0x0
+#define ACP_DAGBO_RD_GO_CNT__onion_rd_only_go_cnt_MASK 0xffff
+#define ACP_DAGBO_RD_GO_CNT__onion_rd_only_go_cnt__SHIFT 0x0
+#define ACP_DAGBO_RD_EXP_RESP_CNT__onion_rd_exp_resp_cnt_MASK 0xffff
+#define ACP_DAGBO_RD_EXP_RESP_CNT__onion_rd_exp_resp_cnt__SHIFT 0x0
+#define ACP_DAGBO_RD_ACTUAL_RESP_CNT__onion_rd_actual_resp_cnt_MASK 0xffff
+#define ACP_DAGBO_RD_ACTUAL_RESP_CNT__onion_rd_actual_resp_cnt__SHIFT 0x0
+#define ACP_BRB_CONTROL__BRB_BlockSharedRAMArbCntrl_MASK 0xf
+#define ACP_BRB_CONTROL__BRB_BlockSharedRAMArbCntrl__SHIFT 0x0
+#define ACP_EXTERNAL_INTR_ENB__ACPExtIntrEnb_MASK 0x1
+#define ACP_EXTERNAL_INTR_ENB__ACPExtIntrEnb__SHIFT 0x0
+#define ACP_EXTERNAL_INTR_CNTL__ACPErrMask_MASK 0x1
+#define ACP_EXTERNAL_INTR_CNTL__ACPErrMask__SHIFT 0x0
+#define ACP_EXTERNAL_INTR_CNTL__I2SMicDataAvMask_MASK 0x2
+#define ACP_EXTERNAL_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1
+#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4
+#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2
+#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8
+#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3
+#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataAvMask_MASK 0x10
+#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4
+#define ACP_EXTERNAL_INTR_CNTL__AzaliaIntrMask_MASK 0x40
+#define ACP_EXTERNAL_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6
+#define ACP_EXTERNAL_INTR_CNTL__DSP0TimeoutMask_MASK 0x100
+#define ACP_EXTERNAL_INTR_CNTL__DSP0TimeoutMask__SHIFT 0x8
+#define ACP_EXTERNAL_INTR_CNTL__DSP1TimeoutMask_MASK 0x200
+#define ACP_EXTERNAL_INTR_CNTL__DSP1TimeoutMask__SHIFT 0x9
+#define ACP_EXTERNAL_INTR_CNTL__DSP2TimeoutMask_MASK 0x400
+#define ACP_EXTERNAL_INTR_CNTL__DSP2TimeoutMask__SHIFT 0xa
+#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x800
+#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xb
+#define ACP_EXTERNAL_INTR_CNTL__DMAIOCMask_MASK 0xffff0000
+#define ACP_EXTERNAL_INTR_CNTL__DMAIOCMask__SHIFT 0x10
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErr_MASK 0x1
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErr__SHIFT 0x0
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSource_MASK 0xe
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSource__SHIFT 0x1
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSourceOver_MASK 0x10
+#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSourceOver__SHIFT 0x4
+#define ACP_ERROR_SOURCE_STS__BRBAddrErr_MASK 0x20
+#define ACP_ERROR_SOURCE_STS__BRBAddrErr__SHIFT 0x5
+#define ACP_ERROR_SOURCE_STS__BRBAddrErrSource_MASK 0x3c0
+#define ACP_ERROR_SOURCE_STS__BRBAddrErrSource__SHIFT 0x6
+#define ACP_ERROR_SOURCE_STS__BRBAddrErrSourceOver_MASK 0x400
+#define ACP_ERROR_SOURCE_STS__BRBAddrErrSourceOver__SHIFT 0xa
+#define ACP_ERROR_SOURCE_STS__I2SMicOverFlowErr_MASK 0x800
+#define ACP_ERROR_SOURCE_STS__I2SMicOverFlowErr__SHIFT 0xb
+#define ACP_ERROR_SOURCE_STS__I2SSpeaker0OverFlowErr_MASK 0x1000
+#define ACP_ERROR_SOURCE_STS__I2SSpeaker0OverFlowErr__SHIFT 0xc
+#define ACP_ERROR_SOURCE_STS__I2SSpeaker1OverFlowErr_MASK 0x2000
+#define ACP_ERROR_SOURCE_STS__I2SSpeaker1OverFlowErr__SHIFT 0xd
+#define ACP_ERROR_SOURCE_STS__I2SBTRxFifoOverFlowErr_MASK 0x4000
+#define ACP_ERROR_SOURCE_STS__I2SBTRxFifoOverFlowErr__SHIFT 0xe
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErr_MASK 0x8000
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErr__SHIFT 0xf
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSource_MASK 0x70000
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSource__SHIFT 0x10
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSourceOver_MASK 0x80000
+#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSourceOver__SHIFT 0x13
+#define ACP_ERROR_SOURCE_STS__DAGBErr_MASK 0x100000
+#define ACP_ERROR_SOURCE_STS__DAGBErr__SHIFT 0x14
+#define ACP_ERROR_SOURCE_STS__DAGBErrSource_MASK 0x1e00000
+#define ACP_ERROR_SOURCE_STS__DAGBErrSource__SHIFT 0x15
+#define ACP_ERROR_SOURCE_STS__DAGBErrSourceOver_MASK 0x2000000
+#define ACP_ERROR_SOURCE_STS__DAGBErrSourceOver__SHIFT 0x19
+#define ACP_ERROR_SOURCE_STS__DMATermOnErr_MASK 0x4000000
+#define ACP_ERROR_SOURCE_STS__DMATermOnErr__SHIFT 0x1a
+#define ACP_ERROR_SOURCE_STS__I2SBTTxFifoOverFlowErr_MASK 0x10000000
+#define ACP_ERROR_SOURCE_STS__I2SBTTxFifoOverFlowErr__SHIFT 0x1c
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP0_MASK 0x1
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP0__SHIFT 0x0
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP1_MASK 0x2
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP1__SHIFT 0x1
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP2_MASK 0x4
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP2__SHIFT 0x2
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP0_MASK 0x100
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP0__SHIFT 0x8
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP1_MASK 0x200
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP1__SHIFT 0x9
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP2_MASK 0x400
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP2__SHIFT 0xa
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP0Host_MASK 0x10000
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP0Host__SHIFT 0x10
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP1Host_MASK 0x20000
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP1Host__SHIFT 0x11
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP2Host_MASK 0x40000
+#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP2Host__SHIFT 0x12
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP0_MASK 0x1
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP0__SHIFT 0x0
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP1_MASK 0x2
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP1__SHIFT 0x1
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP2_MASK 0x4
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP2__SHIFT 0x2
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP0_MASK 0x100
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP0__SHIFT 0x8
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP1_MASK 0x200
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP1__SHIFT 0x9
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP2_MASK 0x400
+#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP2__SHIFT 0xa
+#define ACP_DSP_SW_INTR_CNTL__EnbKernelIntrDSP0Mask_MASK 0x10000
+#define ACP_DSP_SW_INTR_CNTL__EnbKernelIntrDSP0Mask__SHIFT 0x10
+#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP1Mask_MASK 0x20000
+#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP1Mask__SHIFT 0x11
+#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP2Mask_MASK 0x40000
+#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP2Mask__SHIFT 0x12
+#define ACP_DAGBG_TIMEOUT_CNTL__DAGBGTimeoutValue_MASK 0x3ffff
+#define ACP_DAGBG_TIMEOUT_CNTL__DAGBGTimeoutValue__SHIFT 0x0
+#define ACP_DAGBG_TIMEOUT_CNTL__CntEn_MASK 0x80000000
+#define ACP_DAGBG_TIMEOUT_CNTL__CntEn__SHIFT 0x1f
+#define ACP_DAGBO_TIMEOUT_CNTL__DAGBOTimeoutValue_MASK 0x3ffff
+#define ACP_DAGBO_TIMEOUT_CNTL__DAGBOTimeoutValue__SHIFT 0x0
+#define ACP_DAGBO_TIMEOUT_CNTL__CntEn_MASK 0x80000000
+#define ACP_DAGBO_TIMEOUT_CNTL__CntEn__SHIFT 0x1f
+#define ACP_EXTERNAL_INTR_STAT__ACPErrStat_MASK 0x1
+#define ACP_EXTERNAL_INTR_STAT__ACPErrStat__SHIFT 0x0
+#define ACP_EXTERNAL_INTR_STAT__ACPErrAck_MASK 0x1
+#define ACP_EXTERNAL_INTR_STAT__ACPErrAck__SHIFT 0x0
+#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvStat_MASK 0x2
+#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1
+#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvAck_MASK 0x2
+#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8
+#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvStat_MASK 0x10
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvAck_MASK 0x10
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4
+#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrStat_MASK 0x40
+#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrStat__SHIFT 0x6
+#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrAck_MASK 0x40
+#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrAck__SHIFT 0x6
+#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutStat_MASK 0x100
+#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutStat__SHIFT 0x8
+#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutAck_MASK 0x100
+#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutAck__SHIFT 0x8
+#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutStat_MASK 0x200
+#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutStat__SHIFT 0x9
+#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutAck_MASK 0x200
+#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutAck__SHIFT 0x9
+#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutStat_MASK 0x400
+#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutStat__SHIFT 0xa
+#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutAck_MASK 0x400
+#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutAck__SHIFT 0xa
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyStat_MASK 0x800
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xb
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyAck_MASK 0x800
+#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xb
+#define ACP_EXTERNAL_INTR_STAT__DMAIOCStat_MASK 0xffff0000
+#define ACP_EXTERNAL_INTR_STAT__DMAIOCStat__SHIFT 0x10
+#define ACP_EXTERNAL_INTR_STAT__DMAIOCAck_MASK 0xffff0000
+#define ACP_EXTERNAL_INTR_STAT__DMAIOCAck__SHIFT 0x10
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Stat_MASK 0x1
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Stat__SHIFT 0x0
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Ack_MASK 0x1
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Ack__SHIFT 0x0
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Stat_MASK 0x2
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Stat__SHIFT 0x1
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Ack_MASK 0x2
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Ack__SHIFT 0x1
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Stat_MASK 0x4
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Stat__SHIFT 0x2
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Ack_MASK 0x4
+#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Ack__SHIFT 0x2
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Stat_MASK 0x100
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Stat__SHIFT 0x8
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Ack_MASK 0x100
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Ack__SHIFT 0x8
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Stat_MASK 0x200
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Stat__SHIFT 0x9
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Ack_MASK 0x200
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Ack__SHIFT 0x9
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Stat_MASK 0x400
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Stat__SHIFT 0xa
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Ack_MASK 0x400
+#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Ack__SHIFT 0xa
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Stat_MASK 0x10000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Stat__SHIFT 0x10
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Ack_MASK 0x10000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Ack__SHIFT 0x10
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Stat_MASK 0x20000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Stat__SHIFT 0x11
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Ack_MASK 0x20000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Ack__SHIFT 0x11
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Stat_MASK 0x40000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Stat__SHIFT 0x12
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Ack_MASK 0x40000
+#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Ack__SHIFT 0x12
+#define ACP_DSP0_INTR_CNTL__ACPErrMask_MASK 0x1
+#define ACP_DSP0_INTR_CNTL__ACPErrMask__SHIFT 0x0
+#define ACP_DSP0_INTR_CNTL__I2SMicDataAvMask_MASK 0x2
+#define ACP_DSP0_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1
+#define ACP_DSP0_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4
+#define ACP_DSP0_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2
+#define ACP_DSP0_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8
+#define ACP_DSP0_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3
+#define ACP_DSP0_INTR_CNTL__I2SBTDataAvMask_MASK 0x10
+#define ACP_DSP0_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4
+#define ACP_DSP0_INTR_CNTL__AzaliaIntrMask_MASK 0x40
+#define ACP_DSP0_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6
+#define ACP_DSP0_INTR_CNTL__SMUMailboxWriteMask_MASK 0x100
+#define ACP_DSP0_INTR_CNTL__SMUMailboxWriteMask__SHIFT 0x8
+#define ACP_DSP0_INTR_CNTL__SMUStutterStatusMask_MASK 0x200
+#define ACP_DSP0_INTR_CNTL__SMUStutterStatusMask__SHIFT 0x9
+#define ACP_DSP0_INTR_CNTL__MCStutterStatusMask_MASK 0x400
+#define ACP_DSP0_INTR_CNTL__MCStutterStatusMask__SHIFT 0xa
+#define ACP_DSP0_INTR_CNTL__DSPExtTimerMask_MASK 0x800
+#define ACP_DSP0_INTR_CNTL__DSPExtTimerMask__SHIFT 0xb
+#define ACP_DSP0_INTR_CNTL__DSPSemRespMask_MASK 0x1000
+#define ACP_DSP0_INTR_CNTL__DSPSemRespMask__SHIFT 0xc
+#define ACP_DSP0_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x2000
+#define ACP_DSP0_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xd
+#define ACP_DSP0_INTR_CNTL__DMAIOCMask_MASK 0xffff0000
+#define ACP_DSP0_INTR_CNTL__DMAIOCMask__SHIFT 0x10
+#define ACP_DSP0_INTR_STAT__ACPErrStat_MASK 0x1
+#define ACP_DSP0_INTR_STAT__ACPErrStat__SHIFT 0x0
+#define ACP_DSP0_INTR_STAT__ACPErrAck_MASK 0x1
+#define ACP_DSP0_INTR_STAT__ACPErrAck__SHIFT 0x0
+#define ACP_DSP0_INTR_STAT__I2SMicDataAvStat_MASK 0x2
+#define ACP_DSP0_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1
+#define ACP_DSP0_INTR_STAT__I2SMicDataAvAck_MASK 0x2
+#define ACP_DSP0_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1
+#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4
+#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2
+#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4
+#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2
+#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8
+#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3
+#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8
+#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3
+#define ACP_DSP0_INTR_STAT__I2SBTDataAvStat_MASK 0x10
+#define ACP_DSP0_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4
+#define ACP_DSP0_INTR_STAT__I2SBTDataAvAck_MASK 0x10
+#define ACP_DSP0_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4
+#define ACP_DSP0_INTR_STAT__AzaliaIntrStat_MASK 0x40
+#define ACP_DSP0_INTR_STAT__AzaliaIntrStat__SHIFT 0x6
+#define ACP_DSP0_INTR_STAT__AzaliaIntrAck_MASK 0x40
+#define ACP_DSP0_INTR_STAT__AzaliaIntrAck__SHIFT 0x6
+#define ACP_DSP0_INTR_STAT__SMUMailboxWriteStat_MASK 0x100
+#define ACP_DSP0_INTR_STAT__SMUMailboxWriteStat__SHIFT 0x8
+#define ACP_DSP0_INTR_STAT__SMUMailboxWriteAck_MASK 0x100
+#define ACP_DSP0_INTR_STAT__SMUMailboxWriteAck__SHIFT 0x8
+#define ACP_DSP0_INTR_STAT__SMUStutterStatusStat_MASK 0x200
+#define ACP_DSP0_INTR_STAT__SMUStutterStatusStat__SHIFT 0x9
+#define ACP_DSP0_INTR_STAT__SMUStutterStatusAck_MASK 0x200
+#define ACP_DSP0_INTR_STAT__SMUStutterStatusAck__SHIFT 0x9
+#define ACP_DSP0_INTR_STAT__MCStutterStatusStat_MASK 0x400
+#define ACP_DSP0_INTR_STAT__MCStutterStatusStat__SHIFT 0xa
+#define ACP_DSP0_INTR_STAT__MCStutterStatusAck_MASK 0x400
+#define ACP_DSP0_INTR_STAT__MCStutterStatusAck__SHIFT 0xa
+#define ACP_DSP0_INTR_STAT__DSPExtTimerStat_MASK 0x800
+#define ACP_DSP0_INTR_STAT__DSPExtTimerStat__SHIFT 0xb
+#define ACP_DSP0_INTR_STAT__DSPExtTimerAck_MASK 0x800
+#define ACP_DSP0_INTR_STAT__DSPExtTimerAck__SHIFT 0xb
+#define ACP_DSP0_INTR_STAT__DSPSemRespStat_MASK 0x1000
+#define ACP_DSP0_INTR_STAT__DSPSemRespStat__SHIFT 0xc
+#define ACP_DSP0_INTR_STAT__DSPSemRespAck_MASK 0x1000
+#define ACP_DSP0_INTR_STAT__DSPSemRespAck__SHIFT 0xc
+#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyStat_MASK 0x2000
+#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xd
+#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyAck_MASK 0x2000
+#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xd
+#define ACP_DSP0_INTR_STAT__DMAIOCStat_MASK 0xffff0000
+#define ACP_DSP0_INTR_STAT__DMAIOCStat__SHIFT 0x10
+#define ACP_DSP0_INTR_STAT__DMAIOCAck_MASK 0xffff0000
+#define ACP_DSP0_INTR_STAT__DMAIOCAck__SHIFT 0x10
+#define ACP_DSP0_TIMEOUT_CNTL__DSP0TimeoutValue_MASK 0x3ffff
+#define ACP_DSP0_TIMEOUT_CNTL__DSP0TimeoutValue__SHIFT 0x0
+#define ACP_DSP0_TIMEOUT_CNTL__CntEn_MASK 0x80000000
+#define ACP_DSP0_TIMEOUT_CNTL__CntEn__SHIFT 0x1f
+#define ACP_DSP1_INTR_CNTL__ACPErrMask_MASK 0x1
+#define ACP_DSP1_INTR_CNTL__ACPErrMask__SHIFT 0x0
+#define ACP_DSP1_INTR_CNTL__I2SMicDataAvMask_MASK 0x2
+#define ACP_DSP1_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1
+#define ACP_DSP1_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4
+#define ACP_DSP1_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2
+#define ACP_DSP1_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8
+#define ACP_DSP1_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3
+#define ACP_DSP1_INTR_CNTL__I2SBTDataAvMask_MASK 0x10
+#define ACP_DSP1_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4
+#define ACP_DSP1_INTR_CNTL__AzaliaIntrMask_MASK 0x40
+#define ACP_DSP1_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6
+#define ACP_DSP1_INTR_CNTL__SMUMailboxWriteMask_MASK 0x100
+#define ACP_DSP1_INTR_CNTL__SMUMailboxWriteMask__SHIFT 0x8
+#define ACP_DSP1_INTR_CNTL__SMUStutterStatusMask_MASK 0x200
+#define ACP_DSP1_INTR_CNTL__SMUStutterStatusMask__SHIFT 0x9
+#define ACP_DSP1_INTR_CNTL__MCStutterStatusMask_MASK 0x400
+#define ACP_DSP1_INTR_CNTL__MCStutterStatusMask__SHIFT 0xa
+#define ACP_DSP1_INTR_CNTL__DSPExtTimerMask_MASK 0x800
+#define ACP_DSP1_INTR_CNTL__DSPExtTimerMask__SHIFT 0xb
+#define ACP_DSP1_INTR_CNTL__DSPSemRespMask_MASK 0x1000
+#define ACP_DSP1_INTR_CNTL__DSPSemRespMask__SHIFT 0xc
+#define ACP_DSP1_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x2000
+#define ACP_DSP1_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xd
+#define ACP_DSP1_INTR_CNTL__DMAIOCMask_MASK 0xffff0000
+#define ACP_DSP1_INTR_CNTL__DMAIOCMask__SHIFT 0x10
+#define ACP_DSP1_INTR_STAT__ACPErrStat_MASK 0x1
+#define ACP_DSP1_INTR_STAT__ACPErrStat__SHIFT 0x0
+#define ACP_DSP1_INTR_STAT__ACPErrAck_MASK 0x1
+#define ACP_DSP1_INTR_STAT__ACPErrAck__SHIFT 0x0
+#define ACP_DSP1_INTR_STAT__I2SMicDataAvStat_MASK 0x2
+#define ACP_DSP1_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1
+#define ACP_DSP1_INTR_STAT__I2SMicDataAvAck_MASK 0x2
+#define ACP_DSP1_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1
+#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4
+#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2
+#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4
+#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2
+#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8
+#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3
+#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8
+#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3
+#define ACP_DSP1_INTR_STAT__I2SBTDataAvStat_MASK 0x10
+#define ACP_DSP1_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4
+#define ACP_DSP1_INTR_STAT__I2SBTDataAvAck_MASK 0x10
+#define ACP_DSP1_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4
+#define ACP_DSP1_INTR_STAT__AzaliaIntrStat_MASK 0x40
+#define ACP_DSP1_INTR_STAT__AzaliaIntrStat__SHIFT 0x6
+#define ACP_DSP1_INTR_STAT__AzaliaIntrAck_MASK 0x40
+#define ACP_DSP1_INTR_STAT__AzaliaIntrAck__SHIFT 0x6
+#define ACP_DSP1_INTR_STAT__SMUMailboxWriteStat_MASK 0x100
+#define ACP_DSP1_INTR_STAT__SMUMailboxWriteStat__SHIFT 0x8
+#define ACP_DSP1_INTR_STAT__SMUMailboxWriteAck_MASK 0x100
+#define ACP_DSP1_INTR_STAT__SMUMailboxWriteAck__SHIFT 0x8
+#define ACP_DSP1_INTR_STAT__SMUStutterStatusStat_MASK 0x200
+#define ACP_DSP1_INTR_STAT__SMUStutterStatusStat__SHIFT 0x9
+#define ACP_DSP1_INTR_STAT__SMUStutterStatusAck_MASK 0x200
+#define ACP_DSP1_INTR_STAT__SMUStutterStatusAck__SHIFT 0x9
+#define ACP_DSP1_INTR_STAT__MCStutterStatusStat_MASK 0x400
+#define ACP_DSP1_INTR_STAT__MCStutterStatusStat__SHIFT 0xa
+#define ACP_DSP1_INTR_STAT__MCStutterStatusAck_MASK 0x400
+#define ACP_DSP1_INTR_STAT__MCStutterStatusAck__SHIFT 0xa
+#define ACP_DSP1_INTR_STAT__DSPExtTimerStat_MASK 0x800
+#define ACP_DSP1_INTR_STAT__DSPExtTimerStat__SHIFT 0xb
+#define ACP_DSP1_INTR_STAT__DSPExtTimerAck_MASK 0x800
+#define ACP_DSP1_INTR_STAT__DSPExtTimerAck__SHIFT 0xb
+#define ACP_DSP1_INTR_STAT__DSPSemRespStat_MASK 0x1000
+#define ACP_DSP1_INTR_STAT__DSPSemRespStat__SHIFT 0xc
+#define ACP_DSP1_INTR_STAT__DSPSemRespAck_MASK 0x1000
+#define ACP_DSP1_INTR_STAT__DSPSemRespAck__SHIFT 0xc
+#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyStat_MASK 0x2000
+#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xd
+#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyAck_MASK 0x2000
+#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xd
+#define ACP_DSP1_INTR_STAT__DMAIOCStat_MASK 0xffff0000
+#define ACP_DSP1_INTR_STAT__DMAIOCStat__SHIFT 0x10
+#define ACP_DSP1_INTR_STAT__DMAIOCAck_MASK 0xffff0000
+#define ACP_DSP1_INTR_STAT__DMAIOCAck__SHIFT 0x10
+#define ACP_DSP1_TIMEOUT_CNTL__DSP1TimeoutValue_MASK 0x3ffff
+#define ACP_DSP1_TIMEOUT_CNTL__DSP1TimeoutValue__SHIFT 0x0
+#define ACP_DSP1_TIMEOUT_CNTL__CntEn_MASK 0x80000000
+#define ACP_DSP1_TIMEOUT_CNTL__CntEn__SHIFT 0x1f
+#define ACP_DSP2_INTR_CNTL__ACPErrMask_MASK 0x1
+#define ACP_DSP2_INTR_CNTL__ACPErrMask__SHIFT 0x0
+#define ACP_DSP2_INTR_CNTL__I2SMicDataAvMask_MASK 0x2
+#define ACP_DSP2_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1
+#define ACP_DSP2_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4
+#define ACP_DSP2_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2
+#define ACP_DSP2_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8
+#define ACP_DSP2_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3
+#define ACP_DSP2_INTR_CNTL__I2SBTDataAvMask_MASK 0x10
+#define ACP_DSP2_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4
+#define ACP_DSP2_INTR_CNTL__AzaliaIntrMask_MASK 0x40
+#define ACP_DSP2_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6
+#define ACP_DSP2_INTR_CNTL__SMUMailboxWriteMask_MASK 0x100
+#define ACP_DSP2_INTR_CNTL__SMUMailboxWriteMask__SHIFT 0x8
+#define ACP_DSP2_INTR_CNTL__SMUStutterStatusMask_MASK 0x200
+#define ACP_DSP2_INTR_CNTL__SMUStutterStatusMask__SHIFT 0x9
+#define ACP_DSP2_INTR_CNTL__MCStutterStatusMask_MASK 0x400
+#define ACP_DSP2_INTR_CNTL__MCStutterStatusMask__SHIFT 0xa
+#define ACP_DSP2_INTR_CNTL__DSPExtTimerMask_MASK 0x800
+#define ACP_DSP2_INTR_CNTL__DSPExtTimerMask__SHIFT 0xb
+#define ACP_DSP2_INTR_CNTL__DSPSemRespMask_MASK 0x1000
+#define ACP_DSP2_INTR_CNTL__DSPSemRespMask__SHIFT 0xc
+#define ACP_DSP2_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x2000
+#define ACP_DSP2_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xd
+#define ACP_DSP2_INTR_CNTL__DMAIOCMask_MASK 0xffff0000
+#define ACP_DSP2_INTR_CNTL__DMAIOCMask__SHIFT 0x10
+#define ACP_DSP2_INTR_STAT__ACPErrStat_MASK 0x1
+#define ACP_DSP2_INTR_STAT__ACPErrStat__SHIFT 0x0
+#define ACP_DSP2_INTR_STAT__ACPErrAck_MASK 0x1
+#define ACP_DSP2_INTR_STAT__ACPErrAck__SHIFT 0x0
+#define ACP_DSP2_INTR_STAT__I2SMicDataAvStat_MASK 0x2
+#define ACP_DSP2_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1
+#define ACP_DSP2_INTR_STAT__I2SMicDataAvAck_MASK 0x2
+#define ACP_DSP2_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1
+#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4
+#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2
+#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4
+#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2
+#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8
+#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3
+#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8
+#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3
+#define ACP_DSP2_INTR_STAT__I2SBTDataAvStat_MASK 0x10
+#define ACP_DSP2_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4
+#define ACP_DSP2_INTR_STAT__I2SBTDataAvAck_MASK 0x10
+#define ACP_DSP2_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4
+#define ACP_DSP2_INTR_STAT__AzaliaIntrStat_MASK 0x40
+#define ACP_DSP2_INTR_STAT__AzaliaIntrStat__SHIFT 0x6
+#define ACP_DSP2_INTR_STAT__AzaliaIntrAck_MASK 0x40
+#define ACP_DSP2_INTR_STAT__AzaliaIntrAck__SHIFT 0x6
+#define ACP_DSP2_INTR_STAT__SMUMailboxWriteStat_MASK 0x100
+#define ACP_DSP2_INTR_STAT__SMUMailboxWriteStat__SHIFT 0x8
+#define ACP_DSP2_INTR_STAT__SMUMailboxWriteAck_MASK 0x100
+#define ACP_DSP2_INTR_STAT__SMUMailboxWriteAck__SHIFT 0x8
+#define ACP_DSP2_INTR_STAT__SMUStutterStatusStat_MASK 0x200
+#define ACP_DSP2_INTR_STAT__SMUStutterStatusStat__SHIFT 0x9
+#define ACP_DSP2_INTR_STAT__SMUStutterStatusAck_MASK 0x200
+#define ACP_DSP2_INTR_STAT__SMUStutterStatusAck__SHIFT 0x9
+#define ACP_DSP2_INTR_STAT__MCStutterStatusStat_MASK 0x400
+#define ACP_DSP2_INTR_STAT__MCStutterStatusStat__SHIFT 0xa
+#define ACP_DSP2_INTR_STAT__MCStutterStatusAck_MASK 0x400
+#define ACP_DSP2_INTR_STAT__MCStutterStatusAck__SHIFT 0xa
+#define ACP_DSP2_INTR_STAT__DSPExtTimerStat_MASK 0x800
+#define ACP_DSP2_INTR_STAT__DSPExtTimerStat__SHIFT 0xb
+#define ACP_DSP2_INTR_STAT__DSPExtTimerAck_MASK 0x800
+#define ACP_DSP2_INTR_STAT__DSPExtTimerAck__SHIFT 0xb
+#define ACP_DSP2_INTR_STAT__DSPSemRespStat_MASK 0x1000
+#define ACP_DSP2_INTR_STAT__DSPSemRespStat__SHIFT 0xc
+#define ACP_DSP2_INTR_STAT__DSPSemRespAck_MASK 0x1000
+#define ACP_DSP2_INTR_STAT__DSPSemRespAck__SHIFT 0xc
+#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyStat_MASK 0x2000
+#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xd
+#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyAck_MASK 0x2000
+#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xd
+#define ACP_DSP2_INTR_STAT__DMAIOCStat_MASK 0xffff0000
+#define ACP_DSP2_INTR_STAT__DMAIOCStat__SHIFT 0x10
+#define ACP_DSP2_INTR_STAT__DMAIOCAck_MASK 0xffff0000
+#define ACP_DSP2_INTR_STAT__DMAIOCAck__SHIFT 0x10
+#define ACP_DSP2_TIMEOUT_CNTL__DSP2TimeoutValue_MASK 0x3ffff
+#define ACP_DSP2_TIMEOUT_CNTL__DSP2TimeoutValue__SHIFT 0x0
+#define ACP_DSP2_TIMEOUT_CNTL__CntEn_MASK 0x80000000
+#define ACP_DSP2_TIMEOUT_CNTL__CntEn__SHIFT 0x1f
+#define ACP_DSP0_EXT_TIMER_CNTL__TimerCount_MASK 0xffffff
+#define ACP_DSP0_EXT_TIMER_CNTL__TimerCount__SHIFT 0x0
+#define ACP_DSP0_EXT_TIMER_CNTL__TimerCntl_MASK 0xc0000000
+#define ACP_DSP0_EXT_TIMER_CNTL__TimerCntl__SHIFT 0x1e
+#define ACP_DSP1_EXT_TIMER_CNTL__TimerCount_MASK 0xffffff
+#define ACP_DSP1_EXT_TIMER_CNTL__TimerCount__SHIFT 0x0
+#define ACP_DSP1_EXT_TIMER_CNTL__TimerCntl_MASK 0xc0000000
+#define ACP_DSP1_EXT_TIMER_CNTL__TimerCntl__SHIFT 0x1e
+#define ACP_DSP2_EXT_TIMER_CNTL__TimerCount_MASK 0xffffff
+#define ACP_DSP2_EXT_TIMER_CNTL__TimerCount__SHIFT 0x0
+#define ACP_DSP2_EXT_TIMER_CNTL__TimerCntl_MASK 0xc0000000
+#define ACP_DSP2_EXT_TIMER_CNTL__TimerCntl__SHIFT 0x1e
+#define ACP_AXI2DAGB_SEM_0__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_0__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_1__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_1__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_2__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_2__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_3__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_3__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_4__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_4__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_5__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_5__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_6__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_6__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_7__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_7__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_8__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_8__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_9__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_9__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_10__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_10__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_11__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_11__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_12__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_12__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_13__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_13__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_14__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_14__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_15__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_15__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_16__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_16__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_17__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_17__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_18__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_18__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_19__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_19__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_20__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_20__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_21__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_21__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_22__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_22__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_23__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_23__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_24__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_24__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_25__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_25__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_26__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_26__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_27__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_27__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_28__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_28__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_29__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_29__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_30__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_30__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_31__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_31__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_32__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_32__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_33__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_33__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_34__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_34__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_35__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_35__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_36__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_36__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_37__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_37__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_38__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_38__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_39__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_39__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_40__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_40__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_41__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_41__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_42__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_42__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_43__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_43__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_44__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_44__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_45__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_45__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_46__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_46__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_AXI2DAGB_SEM_47__AXI2DAGBGblSemReg_MASK 0x1
+#define ACP_AXI2DAGB_SEM_47__AXI2DAGBGblSemReg__SHIFT 0x0
+#define ACP_SRBM_Client_Base_Addr__SRBM_Client_base_addr_MASK 0xff
+#define ACP_SRBM_Client_Base_Addr__SRBM_Client_base_addr__SHIFT 0x0
+#define ACP_SRBM_Client_RDDATA__ReadData_MASK 0xffffffff
+#define ACP_SRBM_Client_RDDATA__ReadData__SHIFT 0x0
+#define ACP_SRBM_Cycle_Sts__SRBM_Client_Sts_MASK 0x1
+#define ACP_SRBM_Cycle_Sts__SRBM_Client_Sts__SHIFT 0x0
+#define ACP_SRBM_Targ_Idx_Addr__SRBM_Targ_Idx_addr_MASK 0x7ffffff
+#define ACP_SRBM_Targ_Idx_Addr__SRBM_Targ_Idx_addr__SHIFT 0x0
+#define ACP_SRBM_Targ_Idx_Data__SRBM_Targ_Idx_Data_MASK 0xffffffff
+#define ACP_SRBM_Targ_Idx_Data__SRBM_Targ_Idx_Data__SHIFT 0x0
+#define ACP_SEMA_ADDR_LOW__ADDR_9_3_MASK 0x7f
+#define ACP_SEMA_ADDR_LOW__ADDR_9_3__SHIFT 0x0
+#define ACP_SEMA_ADDR_HIGH__ADDR_39_10_MASK 0x3fffffff
+#define ACP_SEMA_ADDR_HIGH__ADDR_39_10__SHIFT 0x0
+#define ACP_SEMA_CMD__REQ_CMD_MASK 0xf
+#define ACP_SEMA_CMD__REQ_CMD__SHIFT 0x0
+#define ACP_SEMA_CMD__WR_PHASE_MASK 0x30
+#define ACP_SEMA_CMD__WR_PHASE__SHIFT 0x4
+#define ACP_SEMA_CMD__VMID_EN_MASK 0x80
+#define ACP_SEMA_CMD__VMID_EN__SHIFT 0x7
+#define ACP_SEMA_CMD__VMID_MASK 0xf00
+#define ACP_SEMA_CMD__VMID__SHIFT 0x8
+#define ACP_SEMA_CMD__ATC_MASK 0x1000
+#define ACP_SEMA_CMD__ATC__SHIFT 0xc
+#define ACP_SEMA_STS__REQ_STS_MASK 0x3
+#define ACP_SEMA_STS__REQ_STS__SHIFT 0x0
+#define ACP_SEMA_STS__REQ_RESP_AVAIL_MASK 0x100
+#define ACP_SEMA_STS__REQ_RESP_AVAIL__SHIFT 0x8
+#define ACP_SEMA_REQ__ISSUE_POLL_REQ_MASK 0x1
+#define ACP_SEMA_REQ__ISSUE_POLL_REQ__SHIFT 0x0
+#define ACP_FW_STATUS__RUN_MASK 0x1
+#define ACP_FW_STATUS__RUN__SHIFT 0x0
+#define ACP_FUTURE_REG_ACLK_0__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_ACLK_0__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_ACLK_1__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_ACLK_1__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_ACLK_2__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_ACLK_2__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_ACLK_3__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_ACLK_3__ACPFutureReg__SHIFT 0x0
+#define ACP_FUTURE_REG_ACLK_4__ACPFutureReg_MASK 0xffffffff
+#define ACP_FUTURE_REG_ACLK_4__ACPFutureReg__SHIFT 0x0
+#define ACP_TIMER__ACP_Timer_count_MASK 0xffffffff
+#define ACP_TIMER__ACP_Timer_count__SHIFT 0x0
+#define ACP_TIMER_CNTL__ACP_Timer_control_MASK 0x1
+#define ACP_TIMER_CNTL__ACP_Timer_control__SHIFT 0x0
+#define ACP_DSP0_TIMER__ACP_DSP0_timer_MASK 0xffffff
+#define ACP_DSP0_TIMER__ACP_DSP0_timer__SHIFT 0x0
+#define ACP_DSP1_TIMER__ACP_DSP1_timer_MASK 0xffffff
+#define ACP_DSP1_TIMER__ACP_DSP1_timer__SHIFT 0x0
+#define ACP_DSP2_TIMER__ACP_DSP2_timer_MASK 0xffffff
+#define ACP_DSP2_TIMER__ACP_DSP2_timer__SHIFT 0x0
+#define ACP_I2S_TRANSMIT_BYTE_CNT_HIGH__i2s_sp_tx_byte_cnt_high_MASK 0xffffffff
+#define ACP_I2S_TRANSMIT_BYTE_CNT_HIGH__i2s_sp_tx_byte_cnt_high__SHIFT 0x0
+#define ACP_I2S_TRANSMIT_BYTE_CNT_LOW__i2s_sp_tx_byte_cnt_low_MASK 0xffffffff
+#define ACP_I2S_TRANSMIT_BYTE_CNT_LOW__i2s_sp_tx_byte_cnt_low__SHIFT 0x0
+#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH__i2s_bt_tx_byte_cnt_high_MASK 0xffffffff
+#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH__i2s_bt_tx_byte_cnt_high__SHIFT 0x0
+#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW__i2s_bt_tx_byte_cnt_low_MASK 0xffffffff
+#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW__i2s_bt_tx_byte_cnt_low__SHIFT 0x0
+#define ACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH__i2s_bt_rx_byte_cnt_high_MASK 0xffffffff
+#define ACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH__i2s_bt_rx_byte_cnt_high__SHIFT 0x0
+#define ACP_I2S_BT_RECEIVE_BYTE_CNT_LOW__i2s_bt_rx_byte_cnt_low_MASK 0xffffffff
+#define ACP_I2S_BT_RECEIVE_BYTE_CNT_LOW__i2s_bt_rx_byte_cnt_low__SHIFT 0x0
+#define ACP_DSP0_CS_STATE__DSP0_CS_state_MASK 0x1
+#define ACP_DSP0_CS_STATE__DSP0_CS_state__SHIFT 0x0
+#define ACP_DSP1_CS_STATE__DSP1_CS_state_MASK 0x1
+#define ACP_DSP1_CS_STATE__DSP1_CS_state__SHIFT 0x0
+#define ACP_DSP2_CS_STATE__DSP2_CS_state_MASK 0x1
+#define ACP_DSP2_CS_STATE__DSP2_CS_state__SHIFT 0x0
+#define ACP_SCRATCH_REG_BASE_ADDR__SCRATCH_REG_BASE_ADDR_MASK 0x7ffff
+#define ACP_SCRATCH_REG_BASE_ADDR__SCRATCH_REG_BASE_ADDR__SHIFT 0x0
+#define CC_ACP_EFUSE__DSP0_DISABLE_MASK 0x2
+#define CC_ACP_EFUSE__DSP0_DISABLE__SHIFT 0x1
+#define CC_ACP_EFUSE__DSP1_DISABLE_MASK 0x4
+#define CC_ACP_EFUSE__DSP1_DISABLE__SHIFT 0x2
+#define CC_ACP_EFUSE__DSP2_DISABLE_MASK 0x8
+#define CC_ACP_EFUSE__DSP2_DISABLE__SHIFT 0x3
+#define CC_ACP_EFUSE__ACP_DISABLE_MASK 0x10
+#define CC_ACP_EFUSE__ACP_DISABLE__SHIFT 0x4
+#define ACP_PGFSM_RETAIN_REG__ACP_P1_ON_OFF_MASK 0x1
+#define ACP_PGFSM_RETAIN_REG__ACP_P1_ON_OFF__SHIFT 0x0
+#define ACP_PGFSM_RETAIN_REG__ACP_P2_ON_OFF_MASK 0x2
+#define ACP_PGFSM_RETAIN_REG__ACP_P2_ON_OFF__SHIFT 0x1
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP0_ON_OFF_MASK 0x4
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP0_ON_OFF__SHIFT 0x2
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP1_ON_OFF_MASK 0x8
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP1_ON_OFF__SHIFT 0x3
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP2_ON_OFF_MASK 0x10
+#define ACP_PGFSM_RETAIN_REG__ACP_DSP2_ON_OFF__SHIFT 0x4
+#define ACP_PGFSM_RETAIN_REG__ACP_AZ_ON_OFF_MASK 0x20
+#define ACP_PGFSM_RETAIN_REG__ACP_AZ_ON_OFF__SHIFT 0x5
+#define ACP_PGFSM_CONFIG_REG__FSM_ADDR_MASK 0xff
+#define ACP_PGFSM_CONFIG_REG__FSM_ADDR__SHIFT 0x0
+#define ACP_PGFSM_CONFIG_REG__Power_Down_MASK 0x100
+#define ACP_PGFSM_CONFIG_REG__Power_Down__SHIFT 0x8
+#define ACP_PGFSM_CONFIG_REG__Power_Up_MASK 0x200
+#define ACP_PGFSM_CONFIG_REG__Power_Up__SHIFT 0x9
+#define ACP_PGFSM_CONFIG_REG__P1_Select_MASK 0x400
+#define ACP_PGFSM_CONFIG_REG__P1_Select__SHIFT 0xa
+#define ACP_PGFSM_CONFIG_REG__P2_Select_MASK 0x800
+#define ACP_PGFSM_CONFIG_REG__P2_Select__SHIFT 0xb
+#define ACP_PGFSM_CONFIG_REG__Wr_MASK 0x1000
+#define ACP_PGFSM_CONFIG_REG__Wr__SHIFT 0xc
+#define ACP_PGFSM_CONFIG_REG__Rd_MASK 0x2000
+#define ACP_PGFSM_CONFIG_REG__Rd__SHIFT 0xd
+#define ACP_PGFSM_CONFIG_REG__RdData_Reset_MASK 0x4000
+#define ACP_PGFSM_CONFIG_REG__RdData_Reset__SHIFT 0xe
+#define ACP_PGFSM_CONFIG_REG__Short_Format_MASK 0x8000
+#define ACP_PGFSM_CONFIG_REG__Short_Format__SHIFT 0xf
+#define ACP_PGFSM_CONFIG_REG__BPM_CG_MG_FGCG_MASK 0x3ff0000
+#define ACP_PGFSM_CONFIG_REG__BPM_CG_MG_FGCG__SHIFT 0x10
+#define ACP_PGFSM_CONFIG_REG__SRBM_override_MASK 0x4000000
+#define ACP_PGFSM_CONFIG_REG__SRBM_override__SHIFT 0x1a
+#define ACP_PGFSM_CONFIG_REG__Rsvd_BPM_Addr_MASK 0x8000000
+#define ACP_PGFSM_CONFIG_REG__Rsvd_BPM_Addr__SHIFT 0x1b
+#define ACP_PGFSM_CONFIG_REG__REG_ADDR_MASK 0xf0000000
+#define ACP_PGFSM_CONFIG_REG__REG_ADDR__SHIFT 0x1c
+#define ACP_PGFSM_WRITE_REG__Write_value_MASK 0xffffffff
+#define ACP_PGFSM_WRITE_REG__Write_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_0__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_0__Read_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_1__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_1__Read_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_2__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_2__Read_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_3__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_3__Read_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_4__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_4__Read_value__SHIFT 0x0
+#define ACP_PGFSM_READ_REG_5__Read_value_MASK 0xffffff
+#define ACP_PGFSM_READ_REG_5__Read_value__SHIFT 0x0
+#define ACP_IP_PGFSM_ENABLE__ACP_IP_ACCESS_MASK 0x1
+#define ACP_IP_PGFSM_ENABLE__ACP_IP_ACCESS__SHIFT 0x0
+#define ACP_I2S_PIN_CONFIG__ACP_I2S_PIN_CONFIG_MASK 0x3
+#define ACP_I2S_PIN_CONFIG__ACP_I2S_PIN_CONFIG__SHIFT 0x0
+#define ACP_AZALIA_I2S_SELECT__AZ_I2S_SELECT_MASK 0x1
+#define ACP_AZALIA_I2S_SELECT__AZ_I2S_SELECT__SHIFT 0x0
+#define ACP_CHIP_PKG_FOR_PAD_ISOLATION__external_fch_package_MASK 0x1
+#define ACP_CHIP_PKG_FOR_PAD_ISOLATION__external_fch_package__SHIFT 0x0
+#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pullup_disable_MASK 0x7ff
+#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pullup_disable__SHIFT 0x0
+#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pulldown_enable_MASK 0x7ff0000
+#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pulldown_enable__SHIFT 0x10
+#define ACP_BT_UART_PAD_SEL__ACP_BT_UART_PAD_SEL_MASK 0x1
+#define ACP_BT_UART_PAD_SEL__ACP_BT_UART_PAD_SEL__SHIFT 0x0
+#define ACP_SCRATCH_REG_0__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_0__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_1__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_1__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_2__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_2__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_3__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_3__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_4__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_4__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_5__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_5__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_6__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_6__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_7__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_7__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_8__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_8__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_9__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_9__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_10__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_10__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_11__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_11__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_12__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_12__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_13__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_13__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_14__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_14__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_15__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_15__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_16__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_16__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_17__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_17__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_18__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_18__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_19__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_19__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_20__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_20__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_21__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_21__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_22__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_22__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_23__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_23__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_24__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_24__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_25__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_25__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_26__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_26__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_27__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_27__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_28__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_28__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_29__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_29__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_30__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_30__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_31__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_31__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_32__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_32__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_33__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_33__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_34__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_34__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_35__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_35__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_36__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_36__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_37__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_37__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_38__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_38__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_39__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_39__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_40__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_40__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_41__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_41__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_42__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_42__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_43__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_43__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_44__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_44__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_45__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_45__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_46__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_46__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_SCRATCH_REG_47__ACP_SCRATCH_REG_MASK 0xffffffff
+#define ACP_SCRATCH_REG_47__ACP_SCRATCH_REG__SHIFT 0x0
+#define ACP_VOICE_WAKEUP_ENABLE__voice_wakeup_enable_MASK 0x1
+#define ACP_VOICE_WAKEUP_ENABLE__voice_wakeup_enable__SHIFT 0x0
+#define ACP_VOICE_WAKEUP_STATUS__voice_wakeup_status_MASK 0x1
+#define ACP_VOICE_WAKEUP_STATUS__voice_wakeup_status__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_LOWER_THRESHOLD__i2s_voice_wakeup_lower_threshold_MASK 0xffffffff
+#define I2S_VOICE_WAKEUP_LOWER_THRESHOLD__i2s_voice_wakeup_lower_threshold__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_HIGHER_THRESHOLD__i2s_voice_wakeup_higher_threshold_MASK 0xffffffff
+#define I2S_VOICE_WAKEUP_HIGHER_THRESHOLD__i2s_voice_wakeup_higher_threshold__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_NO_OF_SAMPLES__i2s_voice_wakeup_no_of_samples_MASK 0xffff
+#define I2S_VOICE_WAKEUP_NO_OF_SAMPLES__i2s_voice_wakeup_no_of_samples__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_NO_OF_PEAKS__i2s_voice_wakeup_no_of_peaks_MASK 0xffff
+#define I2S_VOICE_WAKEUP_NO_OF_PEAKS__i2s_voice_wakeup_no_of_peaks__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_DURATION_OF_N_PEAKS__i2s_voice_wakeup_duration_of_n_peaks_MASK 0xffffffff
+#define I2S_VOICE_WAKEUP_DURATION_OF_N_PEAKS__i2s_voice_wakeup_duration_of_n_peaks__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_BITCLK_TOGGLE_DETECTION__i2s_voice_wakeup_bitclk_toggle_wakeup_en_MASK 0x1
+#define I2S_VOICE_WAKEUP_BITCLK_TOGGLE_DETECTION__i2s_voice_wakeup_bitclk_toggle_wakeup_en__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_req_MASK 0x1
+#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_req__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_ack_MASK 0x2
+#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_ack__SHIFT 0x1
+#define I2S_VOICE_WAKEUP_DATA_POINTER__i2s_voice_wakeup_data_pointer_MASK 0xffffffff
+#define I2S_VOICE_WAKEUP_DATA_POINTER__i2s_voice_wakeup_data_pointer__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_valid_MASK 0x1
+#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_valid__SHIFT 0x0
+#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_match_MASK 0x2
+#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_match__SHIFT 0x1
+#define I2S_VOICE_WAKEUP_8KB_WRAP__i2s_voice_wakeup_8kb_wrap_MASK 0x1
+#define I2S_VOICE_WAKEUP_8KB_WRAP__i2s_voice_wakeup_8kb_wrap__SHIFT 0x0
+#define ACP_I2S_RECEIVED_BYTE_CNT_HIGH__i2s_mic_rx_byte_cnt_high_MASK 0xffffffff
+#define ACP_I2S_RECEIVED_BYTE_CNT_HIGH__i2s_mic_rx_byte_cnt_high__SHIFT 0x0
+#define ACP_I2S_RECEIVED_BYTE_CNT_LOW__i2s_mic_rx_byte_cnt_low_MASK 0xffffffff
+#define ACP_I2S_RECEIVED_BYTE_CNT_LOW__i2s_mic_rx_byte_cnt_low__SHIFT 0x0
+#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH__i2s_micsp_tx_byte_cnt_high_MASK 0xffffffff
+#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH__i2s_micsp_tx_byte_cnt_high__SHIFT 0x0
+#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW__i2s_micsp_tx_byte_cnt_low_MASK 0xffffffff
+#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW__i2s_micsp_tx_byte_cnt_low__SHIFT 0x0
+#define ACP_MEM_SHUT_DOWN_REQ_LO__ACP_ShutDownReq_RAML_MASK 0xffffffff
+#define ACP_MEM_SHUT_DOWN_REQ_LO__ACP_ShutDownReq_RAML__SHIFT 0x0
+#define ACP_MEM_SHUT_DOWN_REQ_HI__ACP_ShutDownReq_RAMH_MASK 0xffff
+#define ACP_MEM_SHUT_DOWN_REQ_HI__ACP_ShutDownReq_RAMH__SHIFT 0x0
+#define ACP_MEM_SHUT_DOWN_STS_LO__ACP_ShutDownSts_RAML_MASK 0xffffffff
+#define ACP_MEM_SHUT_DOWN_STS_LO__ACP_ShutDownSts_RAML__SHIFT 0x0
+#define ACP_MEM_SHUT_DOWN_STS_HI__ACP_ShutDownSts_RAMH_MASK 0xffff
+#define ACP_MEM_SHUT_DOWN_STS_HI__ACP_ShutDownSts_RAMH__SHIFT 0x0
+#define ACP_MEM_DEEP_SLEEP_REQ_LO__ACP_DeepSleepReq_RAML_MASK 0xffffffff
+#define ACP_MEM_DEEP_SLEEP_REQ_LO__ACP_DeepSleepReq_RAML__SHIFT 0x0
+#define ACP_MEM_DEEP_SLEEP_REQ_HI__ACP_DeepSleepReq_RAMH_MASK 0xffff
+#define ACP_MEM_DEEP_SLEEP_REQ_HI__ACP_DeepSleepReq_RAMH__SHIFT 0x0
+#define ACP_MEM_DEEP_SLEEP_STS_LO__ACP_DeepSleepSts_RAML_MASK 0xffffffff
+#define ACP_MEM_DEEP_SLEEP_STS_LO__ACP_DeepSleepSts_RAML__SHIFT 0x0
+#define ACP_MEM_DEEP_SLEEP_STS_HI__ACP_DeepSleepSts_RAMH_MASK 0xffff
+#define ACP_MEM_DEEP_SLEEP_STS_HI__ACP_DeepSleepSts_RAMH__SHIFT 0x0
+#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_LO__acp_mem_wakeup_from_shut_down_lo_MASK 0xffffffff
+#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_LO__acp_mem_wakeup_from_shut_down_lo__SHIFT 0x0
+#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_HI__acp_mem_wakeup_from_shut_down_hi_MASK 0xffff
+#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_HI__acp_mem_wakeup_from_shut_down_hi__SHIFT 0x0
+#define ACP_MEM_WAKEUP_FROM_SLEEP_LO__acp_mem_wakeup_from_sleep_lo_MASK 0xffffffff
+#define ACP_MEM_WAKEUP_FROM_SLEEP_LO__acp_mem_wakeup_from_sleep_lo__SHIFT 0x0
+#define ACP_MEM_WAKEUP_FROM_SLEEP_HI__acp_mem_wakeup_from_sleep_hi_MASK 0xffff
+#define ACP_MEM_WAKEUP_FROM_SLEEP_HI__acp_mem_wakeup_from_sleep_hi__SHIFT 0x0
+#define ACP_I2SSP_IER__I2SSP_IEN_MASK 0x1
+#define ACP_I2SSP_IER__I2SSP_IEN__SHIFT 0x0
+#define ACP_I2SSP_IRER__I2SSP_RXEN_MASK 0x1
+#define ACP_I2SSP_IRER__I2SSP_RXEN__SHIFT 0x0
+#define ACP_I2SSP_ITER__I2SSP_TXEN_MASK 0x1
+#define ACP_I2SSP_ITER__I2SSP_TXEN__SHIFT 0x0
+#define ACP_I2SSP_CER__I2SSP_CLKEN_MASK 0x1
+#define ACP_I2SSP_CER__I2SSP_CLKEN__SHIFT 0x0
+#define ACP_I2SSP_CCR__I2SSP_SCLKG_MASK 0x7
+#define ACP_I2SSP_CCR__I2SSP_SCLKG__SHIFT 0x0
+#define ACP_I2SSP_CCR__I2SSP_WSS_MASK 0x18
+#define ACP_I2SSP_CCR__I2SSP_WSS__SHIFT 0x3
+#define ACP_I2SSP_RXFFR__I2SSP_RXFFR_MASK 0x1
+#define ACP_I2SSP_RXFFR__I2SSP_RXFFR__SHIFT 0x0
+#define ACP_I2SSP_TXFFR__I2SSP_TXFFR_MASK 0x1
+#define ACP_I2SSP_TXFFR__I2SSP_TXFFR__SHIFT 0x0
+#define ACP_I2SSP_LRBR0__I2SSP_LRBR0_MASK 0xffffffff
+#define ACP_I2SSP_LRBR0__I2SSP_LRBR0__SHIFT 0x0
+#define ACP_I2SSP_RRBR0__I2SSP_RRBR0_MASK 0xffffffff
+#define ACP_I2SSP_RRBR0__I2SSP_RRBR0__SHIFT 0x0
+#define ACP_I2SSP_RER0__I2SSP_RXCHEN0_MASK 0x1
+#define ACP_I2SSP_RER0__I2SSP_RXCHEN0__SHIFT 0x0
+#define ACP_I2SSP_TER0__I2SSP_TXCHEN0_MASK 0x1
+#define ACP_I2SSP_TER0__I2SSP_TXCHEN0__SHIFT 0x0
+#define ACP_I2SSP_RCR0__I2SSP_WLEN_MASK 0x7
+#define ACP_I2SSP_RCR0__I2SSP_WLEN__SHIFT 0x0
+#define ACP_I2SSP_TCR0__I2SSP_WLEN_MASK 0x7
+#define ACP_I2SSP_TCR0__I2SSP_WLEN__SHIFT 0x0
+#define ACP_I2SSP_ISR0__I2SSP_RXDA_MASK 0x1
+#define ACP_I2SSP_ISR0__I2SSP_RXDA__SHIFT 0x0
+#define ACP_I2SSP_ISR0__I2SSP_RXFO_MASK 0x2
+#define ACP_I2SSP_ISR0__I2SSP_RXFO__SHIFT 0x1
+#define ACP_I2SSP_ISR0__I2SSP_TXFE_MASK 0x10
+#define ACP_I2SSP_ISR0__I2SSP_TXFE__SHIFT 0x4
+#define ACP_I2SSP_ISR0__I2SSP_TXFO_MASK 0x20
+#define ACP_I2SSP_ISR0__I2SSP_TXFO__SHIFT 0x5
+#define ACP_I2SSP_IMR0__I2SSP_RXDAM_MASK 0x1
+#define ACP_I2SSP_IMR0__I2SSP_RXDAM__SHIFT 0x0
+#define ACP_I2SSP_IMR0__I2SSP_RXFOM_MASK 0x2
+#define ACP_I2SSP_IMR0__I2SSP_RXFOM__SHIFT 0x1
+#define ACP_I2SSP_IMR0__I2SSP_TXFEM_MASK 0x10
+#define ACP_I2SSP_IMR0__I2SSP_TXFEM__SHIFT 0x4
+#define ACP_I2SSP_IMR0__I2SSP_TXFOM_MASK 0x20
+#define ACP_I2SSP_IMR0__I2SSP_TXFOM__SHIFT 0x5
+#define ACP_I2SSP_ROR0__I2SSP_RXCHO_MASK 0x1
+#define ACP_I2SSP_ROR0__I2SSP_RXCHO__SHIFT 0x0
+#define ACP_I2SSP_TOR0__I2SSP_TXCHO_MASK 0x1
+#define ACP_I2SSP_TOR0__I2SSP_TXCHO__SHIFT 0x0
+#define ACP_I2SSP_RFCR0__I2SSP_RXCHDT_MASK 0xf
+#define ACP_I2SSP_RFCR0__I2SSP_RXCHDT__SHIFT 0x0
+#define ACP_I2SSP_TFCR0__I2SSP_TXCHET_MASK 0xf
+#define ACP_I2SSP_TFCR0__I2SSP_TXCHET__SHIFT 0x0
+#define ACP_I2SSP_RFF0__I2SSP_RXCHFR_MASK 0x1
+#define ACP_I2SSP_RFF0__I2SSP_RXCHFR__SHIFT 0x0
+#define ACP_I2SSP_TFF0__I2SSP_TXCHFR_MASK 0x1
+#define ACP_I2SSP_TFF0__I2SSP_TXCHFR__SHIFT 0x0
+#define ACP_I2SSP_RXDMA__I2SSP_RXDMA_MASK 0xffffffff
+#define ACP_I2SSP_RXDMA__I2SSP_RXDMA__SHIFT 0x0
+#define ACP_I2SSP_RRXDMA__I2SSP_RRXDMA_MASK 0x1
+#define ACP_I2SSP_RRXDMA__I2SSP_RRXDMA__SHIFT 0x0
+#define ACP_I2SSP_TXDMA__I2SSP_TXDMA_MASK 0xffffffff
+#define ACP_I2SSP_TXDMA__I2SSP_TXDMA__SHIFT 0x0
+#define ACP_I2SSP_RTXDMA__I2SSP_RTXDMA_MASK 0x1
+#define ACP_I2SSP_RTXDMA__I2SSP_RTXDMA__SHIFT 0x0
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_0_MASK 0x7
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_0__SHIFT 0x0
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_1_MASK 0x38
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_1__SHIFT 0x3
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_2_MASK 0x380
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_2__SHIFT 0x7
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_3_MASK 0x1c00
+#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_3__SHIFT 0xa
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_APB_DATA_WIDTH_MASK 0x3
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_FIFO_DEPTH_GLOBAL_MASK 0xc
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_FIFO_DEPTH_GLOBAL__SHIFT 0x2
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_MODE_EN_MASK 0x10
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_MODE_EN__SHIFT 0x4
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TRANSMITTER_BLOCK_MASK 0x20
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TRANSMITTER_BLOCK__SHIFT 0x5
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RECEIVER_BLOCK_MASK 0x40
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RECEIVER_BLOCK__SHIFT 0x6
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RX_CHANNLES_MASK 0x180
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RX_CHANNLES__SHIFT 0x7
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_CHANNLES_MASK 0x600
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_CHANNLES__SHIFT 0x9
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_0_MASK 0x70000
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_0__SHIFT 0x10
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_1_MASK 0x380000
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_1__SHIFT 0x13
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_2_MASK 0x1c00000
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_2__SHIFT 0x16
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_3_MASK 0xe000000
+#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_3__SHIFT 0x19
+#define ACP_I2SSP_COMP_VERSION__I2SSP_APB_DATA_WIDTH_MASK 0xffffffff
+#define ACP_I2SSP_COMP_VERSION__I2SSP_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SSP_COMP_TYPE__I2SSP_COMP_TYPE_MASK 0xffffffff
+#define ACP_I2SSP_COMP_TYPE__I2SSP_COMP_TYPE__SHIFT 0x0
+#define ACP_I2SMICSP_IER__I2SMICSP_IEN_MASK 0x1
+#define ACP_I2SMICSP_IER__I2SMICSP_IEN__SHIFT 0x0
+#define ACP_I2SMICSP_IRER__I2SMICSP_RXEN_MASK 0x1
+#define ACP_I2SMICSP_IRER__I2SMICSP_RXEN__SHIFT 0x0
+#define ACP_I2SMICSP_ITER__I2SMICSP_TXEN_MASK 0x1
+#define ACP_I2SMICSP_ITER__I2SMICSP_TXEN__SHIFT 0x0
+#define ACP_I2SMICSP_CER__I2SMICSP_CLKEN_MASK 0x1
+#define ACP_I2SMICSP_CER__I2SMICSP_CLKEN__SHIFT 0x0
+#define ACP_I2SMICSP_CCR__I2SMICSP_SCLKG_MASK 0x7
+#define ACP_I2SMICSP_CCR__I2SMICSP_SCLKG__SHIFT 0x0
+#define ACP_I2SMICSP_CCR__I2SMICSP_WSS_MASK 0x18
+#define ACP_I2SMICSP_CCR__I2SMICSP_WSS__SHIFT 0x3
+#define ACP_I2SMICSP_RXFFR__I2SMICSP_RXFFR_MASK 0x1
+#define ACP_I2SMICSP_RXFFR__I2SMICSP_RXFFR__SHIFT 0x0
+#define ACP_I2SMICSP_TXFFR__I2SMICSP_TXFFR_MASK 0x1
+#define ACP_I2SMICSP_TXFFR__I2SMICSP_TXFFR__SHIFT 0x0
+#define ACP_I2SMICSP_LRBR0__I2SMICSP_LRBR0_MASK 0xffffffff
+#define ACP_I2SMICSP_LRBR0__I2SMICSP_LRBR0__SHIFT 0x0
+#define ACP_I2SMICSP_RRBR0__I2SMICSP_RRBR0_MASK 0xffffffff
+#define ACP_I2SMICSP_RRBR0__I2SMICSP_RRBR0__SHIFT 0x0
+#define ACP_I2SMICSP_RER0__I2SMICSP_RXCHEN0_MASK 0x1
+#define ACP_I2SMICSP_RER0__I2SMICSP_RXCHEN0__SHIFT 0x0
+#define ACP_I2SMICSP_TER0__I2SMICSP_TXCHEN0_MASK 0x1
+#define ACP_I2SMICSP_TER0__I2SMICSP_TXCHEN0__SHIFT 0x0
+#define ACP_I2SMICSP_RCR0__I2SMICSP_WLEN_MASK 0x7
+#define ACP_I2SMICSP_RCR0__I2SMICSP_WLEN__SHIFT 0x0
+#define ACP_I2SMICSP_TCR0__I2SMICSP_WLEN_MASK 0x7
+#define ACP_I2SMICSP_TCR0__I2SMICSP_WLEN__SHIFT 0x0
+#define ACP_I2SMICSP_ISR0__I2SMICSP_RXDA_MASK 0x1
+#define ACP_I2SMICSP_ISR0__I2SMICSP_RXDA__SHIFT 0x0
+#define ACP_I2SMICSP_ISR0__I2SMICSP_RXFO_MASK 0x2
+#define ACP_I2SMICSP_ISR0__I2SMICSP_RXFO__SHIFT 0x1
+#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFE_MASK 0x10
+#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFE__SHIFT 0x4
+#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFO_MASK 0x20
+#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFO__SHIFT 0x5
+#define ACP_I2SMICSP_IMR0__I2SMICSP_RXDAM_MASK 0x1
+#define ACP_I2SMICSP_IMR0__I2SMICSP_RXDAM__SHIFT 0x0
+#define ACP_I2SMICSP_IMR0__I2SMICSP_RXFOM_MASK 0x2
+#define ACP_I2SMICSP_IMR0__I2SMICSP_RXFOM__SHIFT 0x1
+#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFEM_MASK 0x10
+#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFEM__SHIFT 0x4
+#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFOM_MASK 0x20
+#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFOM__SHIFT 0x5
+#define ACP_I2SMICSP_ROR0__I2SMICSP_RXCHO_MASK 0x1
+#define ACP_I2SMICSP_ROR0__I2SMICSP_RXCHO__SHIFT 0x0
+#define ACP_I2SMICSP_TOR0__I2SMICSP_TXCHO_MASK 0x1
+#define ACP_I2SMICSP_TOR0__I2SMICSP_TXCHO__SHIFT 0x0
+#define ACP_I2SMICSP_RFCR0__I2SMICSP_RXCHDT_MASK 0xf
+#define ACP_I2SMICSP_RFCR0__I2SMICSP_RXCHDT__SHIFT 0x0
+#define ACP_I2SMICSP_TFCR0__I2SMICSP_TXCHET_MASK 0xf
+#define ACP_I2SMICSP_TFCR0__I2SMICSP_TXCHET__SHIFT 0x0
+#define ACP_I2SMICSP_RFF0__I2SMICSP_RXCHFR_MASK 0x1
+#define ACP_I2SMICSP_RFF0__I2SMICSP_RXCHFR__SHIFT 0x0
+#define ACP_I2SMICSP_TFF0__I2SMICSP_TXCHFR_MASK 0x1
+#define ACP_I2SMICSP_TFF0__I2SMICSP_TXCHFR__SHIFT 0x0
+#define ACP_I2SMICSP_LRBR1__I2SMICSP_LRBR1_MASK 0xffffffff
+#define ACP_I2SMICSP_LRBR1__I2SMICSP_LRBR1__SHIFT 0x0
+#define ACP_I2SMICSP_RRBR1__I2SMICSP_RRBR1_MASK 0xffffffff
+#define ACP_I2SMICSP_RRBR1__I2SMICSP_RRBR1__SHIFT 0x0
+#define ACP_I2SMICSP_RER1__I2SMICSP_RXCHEN1_MASK 0x1
+#define ACP_I2SMICSP_RER1__I2SMICSP_RXCHEN1__SHIFT 0x0
+#define ACP_I2SMICSP_TER1__I2SMICSP_TXCHEN1_MASK 0x1
+#define ACP_I2SMICSP_TER1__I2SMICSP_TXCHEN1__SHIFT 0x0
+#define ACP_I2SMICSP_RCR1__I2SMICSP_WLEN_MASK 0x7
+#define ACP_I2SMICSP_RCR1__I2SMICSP_WLEN__SHIFT 0x0
+#define ACP_I2SMICSP_TCR1__I2SMICSP_WLEN_MASK 0x7
+#define ACP_I2SMICSP_TCR1__I2SMICSP_WLEN__SHIFT 0x0
+#define ACP_I2SMICSP_ISR1__I2SMICSP_RXDA_MASK 0x1
+#define ACP_I2SMICSP_ISR1__I2SMICSP_RXDA__SHIFT 0x0
+#define ACP_I2SMICSP_ISR1__I2SMICSP_RXFO_MASK 0x2
+#define ACP_I2SMICSP_ISR1__I2SMICSP_RXFO__SHIFT 0x1
+#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFE_MASK 0x10
+#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFE__SHIFT 0x4
+#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFO_MASK 0x20
+#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFO__SHIFT 0x5
+#define ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM_MASK 0x1
+#define ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM__SHIFT 0x0
+#define ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM_MASK 0x2
+#define ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM__SHIFT 0x1
+#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFEM_MASK 0x10
+#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFEM__SHIFT 0x4
+#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFOM_MASK 0x20
+#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFOM__SHIFT 0x5
+#define ACP_I2SMICSP_ROR1__I2SMICSP_RXCHO_MASK 0x1
+#define ACP_I2SMICSP_ROR1__I2SMICSP_RXCHO__SHIFT 0x0
+#define ACP_I2SMICSP_TOR1__I2SMICSP_TXCHO_MASK 0x1
+#define ACP_I2SMICSP_TOR1__I2SMICSP_TXCHO__SHIFT 0x0
+#define ACP_I2SMICSP_RFCR1__I2SMICSP_RXCHDT_MASK 0xf
+#define ACP_I2SMICSP_RFCR1__I2SMICSP_RXCHDT__SHIFT 0x0
+#define ACP_I2SMICSP_TFCR1__I2SMICSP_TXCHET_MASK 0xf
+#define ACP_I2SMICSP_TFCR1__I2SMICSP_TXCHET__SHIFT 0x0
+#define ACP_I2SMICSP_RFF1__I2SMICSP_RXCHFR_MASK 0x1
+#define ACP_I2SMICSP_RFF1__I2SMICSP_RXCHFR__SHIFT 0x0
+#define ACP_I2SMICSP_TFF1__I2SMICSP_TXCHFR_MASK 0x1
+#define ACP_I2SMICSP_TFF1__I2SMICSP_TXCHFR__SHIFT 0x0
+#define ACP_I2SMICSP_RXDMA__I2SMICSP_RXDMA_MASK 0xffffffff
+#define ACP_I2SMICSP_RXDMA__I2SMICSP_RXDMA__SHIFT 0x0
+#define ACP_I2SMICSP_RRXDMA__I2SMICSP_RRXDMA_MASK 0x1
+#define ACP_I2SMICSP_RRXDMA__I2SMICSP_RRXDMA__SHIFT 0x0
+#define ACP_I2SMICSP_TXDMA__I2SMICSP_TXDMA_MASK 0xffffffff
+#define ACP_I2SMICSP_TXDMA__I2SMICSP_TXDMA__SHIFT 0x0
+#define ACP_I2SMICSP_RTXDMA__I2SMICSP_RTXDMA_MASK 0x1
+#define ACP_I2SMICSP_RTXDMA__I2SMICSP_RTXDMA__SHIFT 0x0
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_0_MASK 0x7
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_0__SHIFT 0x0
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_1_MASK 0x38
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_1__SHIFT 0x3
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_2_MASK 0x380
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_2__SHIFT 0x7
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_3_MASK 0x1c00
+#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_3__SHIFT 0xa
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_APB_DATA_WIDTH_MASK 0x3
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_FIFO_DEPTH_GLOBAL_MASK 0xc
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_FIFO_DEPTH_GLOBAL__SHIFT 0x2
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_MODE_EN_MASK 0x10
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_MODE_EN__SHIFT 0x4
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TRANSMITTER_BLOCK_MASK 0x20
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TRANSMITTER_BLOCK__SHIFT 0x5
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RECEIVER_BLOCK_MASK 0x40
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RECEIVER_BLOCK__SHIFT 0x6
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RX_CHANNLES_MASK 0x180
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RX_CHANNLES__SHIFT 0x7
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_CHANNLES_MASK 0x600
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_CHANNLES__SHIFT 0x9
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_0_MASK 0x70000
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_0__SHIFT 0x10
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_1_MASK 0x380000
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_1__SHIFT 0x13
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_2_MASK 0x1c00000
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_2__SHIFT 0x16
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_3_MASK 0xe000000
+#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_3__SHIFT 0x19
+#define ACP_I2SMICSP_COMP_VERSION__I2SMICSP_APB_DATA_WIDTH_MASK 0xffffffff
+#define ACP_I2SMICSP_COMP_VERSION__I2SMICSP_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SMICSP_COMP_TYPE__I2SMICSP_COMP_TYPE_MASK 0xffffffff
+#define ACP_I2SMICSP_COMP_TYPE__I2SMICSP_COMP_TYPE__SHIFT 0x0
+#define ACP_I2SBT_IER__I2SBT_IEN_MASK 0x1
+#define ACP_I2SBT_IER__I2SBT_IEN__SHIFT 0x0
+#define ACP_I2SBT_IRER__I2SBT_RXEN_MASK 0x1
+#define ACP_I2SBT_IRER__I2SBT_RXEN__SHIFT 0x0
+#define ACP_I2SBT_ITER__I2SBT_TXEN_MASK 0x1
+#define ACP_I2SBT_ITER__I2SBT_TXEN__SHIFT 0x0
+#define ACP_I2SBT_CER__I2SBT_CLKEN_MASK 0x1
+#define ACP_I2SBT_CER__I2SBT_CLKEN__SHIFT 0x0
+#define ACP_I2SBT_CCR__I2SBT_SCLKG_MASK 0x7
+#define ACP_I2SBT_CCR__I2SBT_SCLKG__SHIFT 0x0
+#define ACP_I2SBT_CCR__I2SBT_WSS_MASK 0x18
+#define ACP_I2SBT_CCR__I2SBT_WSS__SHIFT 0x3
+#define ACP_I2SBT_RXFFR__I2SBT_RXFFR_MASK 0x1
+#define ACP_I2SBT_RXFFR__I2SBT_RXFFR__SHIFT 0x0
+#define ACP_I2SBT_TXFFR__I2SBT_TXFFR_MASK 0x1
+#define ACP_I2SBT_TXFFR__I2SBT_TXFFR__SHIFT 0x0
+#define ACP_I2SBT_LRBR0__I2SBT_LRBR0_MASK 0xffffffff
+#define ACP_I2SBT_LRBR0__I2SBT_LRBR0__SHIFT 0x0
+#define ACP_I2SBT_RRBR0__I2SBT_RRBR0_MASK 0xffffffff
+#define ACP_I2SBT_RRBR0__I2SBT_RRBR0__SHIFT 0x0
+#define ACP_I2SBT_RER0__I2SBT_RXCHEN0_MASK 0x1
+#define ACP_I2SBT_RER0__I2SBT_RXCHEN0__SHIFT 0x0
+#define ACP_I2SBT_TER0__I2SBT_TXCHEN0_MASK 0x1
+#define ACP_I2SBT_TER0__I2SBT_TXCHEN0__SHIFT 0x0
+#define ACP_I2SBT_RCR0__I2SBT_WLEN_MASK 0x7
+#define ACP_I2SBT_RCR0__I2SBT_WLEN__SHIFT 0x0
+#define ACP_I2SBT_TCR0__I2SBT_WLEN_MASK 0x7
+#define ACP_I2SBT_TCR0__I2SBT_WLEN__SHIFT 0x0
+#define ACP_I2SBT_ISR0__I2SBT_RXDA_MASK 0x1
+#define ACP_I2SBT_ISR0__I2SBT_RXDA__SHIFT 0x0
+#define ACP_I2SBT_ISR0__I2SBT_RXFO_MASK 0x2
+#define ACP_I2SBT_ISR0__I2SBT_RXFO__SHIFT 0x1
+#define ACP_I2SBT_ISR0__I2SBT_TXFE_MASK 0x10
+#define ACP_I2SBT_ISR0__I2SBT_TXFE__SHIFT 0x4
+#define ACP_I2SBT_ISR0__I2SBT_TXFO_MASK 0x20
+#define ACP_I2SBT_ISR0__I2SBT_TXFO__SHIFT 0x5
+#define ACP_I2SBT_IMR0__I2SBT_RXDAM_MASK 0x1
+#define ACP_I2SBT_IMR0__I2SBT_RXDAM__SHIFT 0x0
+#define ACP_I2SBT_IMR0__I2SBT_RXFOM_MASK 0x2
+#define ACP_I2SBT_IMR0__I2SBT_RXFOM__SHIFT 0x1
+#define ACP_I2SBT_IMR0__I2SBT_TXFEM_MASK 0x10
+#define ACP_I2SBT_IMR0__I2SBT_TXFEM__SHIFT 0x4
+#define ACP_I2SBT_IMR0__I2SBT_TXFOM_MASK 0x20
+#define ACP_I2SBT_IMR0__I2SBT_TXFOM__SHIFT 0x5
+#define ACP_I2SBT_ROR0__I2SBT_RXCHO_MASK 0x1
+#define ACP_I2SBT_ROR0__I2SBT_RXCHO__SHIFT 0x0
+#define ACP_I2SBT_TOR0__I2SBT_TXCHO_MASK 0x1
+#define ACP_I2SBT_TOR0__I2SBT_TXCHO__SHIFT 0x0
+#define ACP_I2SBT_RFCR0__I2SBT_RXCHDT_MASK 0xf
+#define ACP_I2SBT_RFCR0__I2SBT_RXCHDT__SHIFT 0x0
+#define ACP_I2SBT_TFCR0__I2SBT_TXCHET_MASK 0xf
+#define ACP_I2SBT_TFCR0__I2SBT_TXCHET__SHIFT 0x0
+#define ACP_I2SBT_RFF0__I2SBT_RXCHFR_MASK 0x1
+#define ACP_I2SBT_RFF0__I2SBT_RXCHFR__SHIFT 0x0
+#define ACP_I2SBT_TFF0__I2SBT_TXCHFR_MASK 0x1
+#define ACP_I2SBT_TFF0__I2SBT_TXCHFR__SHIFT 0x0
+#define ACP_I2SBT_LRBR1__I2SBT_LRBR1_MASK 0xffffffff
+#define ACP_I2SBT_LRBR1__I2SBT_LRBR1__SHIFT 0x0
+#define ACP_I2SBT_RRBR1__I2SBT_RRBR1_MASK 0xffffffff
+#define ACP_I2SBT_RRBR1__I2SBT_RRBR1__SHIFT 0x0
+#define ACP_I2SBT_RER1__I2SBT_RXCHEN1_MASK 0x1
+#define ACP_I2SBT_RER1__I2SBT_RXCHEN1__SHIFT 0x0
+#define ACP_I2SBT_TER1__I2SBT_TXCHEN1_MASK 0x1
+#define ACP_I2SBT_TER1__I2SBT_TXCHEN1__SHIFT 0x0
+#define ACP_I2SBT_RCR1__I2SBT_WLEN_MASK 0x7
+#define ACP_I2SBT_RCR1__I2SBT_WLEN__SHIFT 0x0
+#define ACP_I2SBT_TCR1__I2SBT_WLEN_MASK 0x7
+#define ACP_I2SBT_TCR1__I2SBT_WLEN__SHIFT 0x0
+#define ACP_I2SBT_ISR1__I2SBT_RXDA_MASK 0x1
+#define ACP_I2SBT_ISR1__I2SBT_RXDA__SHIFT 0x0
+#define ACP_I2SBT_ISR1__I2SBT_RXFO_MASK 0x2
+#define ACP_I2SBT_ISR1__I2SBT_RXFO__SHIFT 0x1
+#define ACP_I2SBT_ISR1__I2SBT_TXFE_MASK 0x10
+#define ACP_I2SBT_ISR1__I2SBT_TXFE__SHIFT 0x4
+#define ACP_I2SBT_ISR1__I2SBT_TXFO_MASK 0x20
+#define ACP_I2SBT_ISR1__I2SBT_TXFO__SHIFT 0x5
+#define ACP_I2SBT_IMR1__I2SBT_RXDAM_MASK 0x1
+#define ACP_I2SBT_IMR1__I2SBT_RXDAM__SHIFT 0x0
+#define ACP_I2SBT_IMR1__I2SBT_RXFOM_MASK 0x2
+#define ACP_I2SBT_IMR1__I2SBT_RXFOM__SHIFT 0x1
+#define ACP_I2SBT_IMR1__I2SBT_TXFEM_MASK 0x10
+#define ACP_I2SBT_IMR1__I2SBT_TXFEM__SHIFT 0x4
+#define ACP_I2SBT_IMR1__I2SBT_TXFOM_MASK 0x20
+#define ACP_I2SBT_IMR1__I2SBT_TXFOM__SHIFT 0x5
+#define ACP_I2SBT_ROR1__I2SBT_RXCHO_MASK 0x1
+#define ACP_I2SBT_ROR1__I2SBT_RXCHO__SHIFT 0x0
+#define ACP_I2SBT_TOR1__I2SBT_TXCHO_MASK 0x1
+#define ACP_I2SBT_TOR1__I2SBT_TXCHO__SHIFT 0x0
+#define ACP_I2SBT_RFCR1__I2SBT_RXCHDT_MASK 0xf
+#define ACP_I2SBT_RFCR1__I2SBT_RXCHDT__SHIFT 0x0
+#define ACP_I2SBT_TFCR1__I2SBT_TXCHET_MASK 0xf
+#define ACP_I2SBT_TFCR1__I2SBT_TXCHET__SHIFT 0x0
+#define ACP_I2SBT_RFF1__I2SBT_RXCHFR_MASK 0x1
+#define ACP_I2SBT_RFF1__I2SBT_RXCHFR__SHIFT 0x0
+#define ACP_I2SBT_TFF1__I2SBT_TXCHFR_MASK 0x1
+#define ACP_I2SBT_TFF1__I2SBT_TXCHFR__SHIFT 0x0
+#define ACP_I2SBT_RXDMA__I2SBT_RXDMA_MASK 0xffffffff
+#define ACP_I2SBT_RXDMA__I2SBT_RXDMA__SHIFT 0x0
+#define ACP_I2SBT_RRXDMA__I2SBT_RRXDMA_MASK 0x1
+#define ACP_I2SBT_RRXDMA__I2SBT_RRXDMA__SHIFT 0x0
+#define ACP_I2SBT_TXDMA__I2SBT_TXDMA_MASK 0xffffffff
+#define ACP_I2SBT_TXDMA__I2SBT_TXDMA__SHIFT 0x0
+#define ACP_I2SBT_RTXDMA__I2SBT_RTXDMA_MASK 0x1
+#define ACP_I2SBT_RTXDMA__I2SBT_RTXDMA__SHIFT 0x0
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_0_MASK 0x7
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_0__SHIFT 0x0
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_1_MASK 0x38
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_1__SHIFT 0x3
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_2_MASK 0x380
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_2__SHIFT 0x7
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_3_MASK 0x1c00
+#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_3__SHIFT 0xa
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_APB_DATA_WIDTH_MASK 0x3
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_FIFO_DEPTH_GLOBAL_MASK 0xc
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_FIFO_DEPTH_GLOBAL__SHIFT 0x2
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_MODE_EN_MASK 0x10
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_MODE_EN__SHIFT 0x4
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TRANSMITTER_BLOCK_MASK 0x20
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TRANSMITTER_BLOCK__SHIFT 0x5
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RECEIVER_BLOCK_MASK 0x40
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RECEIVER_BLOCK__SHIFT 0x6
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RX_CHANNLES_MASK 0x180
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RX_CHANNLES__SHIFT 0x7
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_CHANNLES_MASK 0x600
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_CHANNLES__SHIFT 0x9
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_0_MASK 0x70000
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_0__SHIFT 0x10
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_1_MASK 0x380000
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_1__SHIFT 0x13
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_2_MASK 0x1c00000
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_2__SHIFT 0x16
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_3_MASK 0xe000000
+#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_3__SHIFT 0x19
+#define ACP_I2SBT_COMP_VERSION__I2SBT_APB_DATA_WIDTH_MASK 0xffffffff
+#define ACP_I2SBT_COMP_VERSION__I2SBT_APB_DATA_WIDTH__SHIFT 0x0
+#define ACP_I2SBT_COMP_TYPE__I2SBT_COMP_TYPE_MASK 0xffffffff
+#define ACP_I2SBT_COMP_TYPE__I2SBT_COMP_TYPE__SHIFT 0x0
+
+#endif /* ACP_2_2_SH_MASK_H */
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index 2d30464..06e099e 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -68,4 +68,13 @@
 	help
 	  Say Y if you want to add support for Atmel ASoC driver for boards using
 	  CLASSD.
+
+config SND_ATMEL_SOC_PDMIC
+	tristate "Atmel ASoC driver for boards using PDMIC"
+	depends on OF && (ARCH_AT91 || COMPILE_TEST)
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	select REGMAP_MMIO
+	help
+	  Say Y if you want to add support for Atmel ASoC driver for boards using
+	  PDMIC.
 endif
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile
index f6f7db4..a2b127b 100644
--- a/sound/soc/atmel/Makefile
+++ b/sound/soc/atmel/Makefile
@@ -12,8 +12,10 @@
 snd-atmel-soc-wm8904-objs := atmel_wm8904.o
 snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
 snd-atmel-soc-classd-objs := atmel-classd.o
+snd-atmel-soc-pdmic-objs := atmel-pdmic.o
 
 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
 obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
 obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
 obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o
+obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c
index 8276675..6107de9 100644
--- a/sound/soc/atmel/atmel-classd.c
+++ b/sound/soc/atmel/atmel-classd.c
@@ -106,7 +106,7 @@
 	.rates			= ATMEL_CLASSD_RATES,
 	.rate_min		= 8000,
 	.rate_max		= 96000,
-	.channels_min		= 2,
+	.channels_min		= 1,
 	.channels_max		= 2,
 	.buffer_bytes_max	= 64 * 1024,
 	.period_bytes_min	= 256,
@@ -145,7 +145,7 @@
 
 static struct snd_soc_dai_driver atmel_classd_cpu_dai = {
 	.playback = {
-		.channels_min	= 2,
+		.channels_min	= 1,
 		.channels_max	= 2,
 		.rates		= ATMEL_CLASSD_RATES,
 		.formats	= SNDRV_PCM_FMTBIT_S16_LE,},
@@ -171,9 +171,13 @@
 		return -EINVAL;
 	}
 
+	if (params_channels(params) == 1)
+		slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+	else
+		slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
 	slave_config->direction		= DMA_MEM_TO_DEV;
 	slave_config->dst_addr		= dd->phy_base + CLASSD_THR;
-	slave_config->dst_addr_width	= DMA_SLAVE_BUSWIDTH_4_BYTES;
 	slave_config->dst_maxburst	= 1;
 	slave_config->src_maxburst	= 1;
 	slave_config->device_fc		= false;
@@ -486,7 +490,7 @@
 	.name = ATMEL_CLASSD_CODEC_DAI_NAME,
 	.playback = {
 		.stream_name	= "Playback",
-		.channels_min	= 2,
+		.channels_min	= 1,
 		.channels_max	= 2,
 		.rates		= ATMEL_CLASSD_RATES,
 		.formats	= SNDRV_PCM_FMTBIT_S16_LE,
@@ -636,8 +640,10 @@
 
 	/* register sound card */
 	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
-	if (!card)
-		return -ENOMEM;
+	if (!card) {
+		ret = -ENOMEM;
+		goto unregister_codec;
+	}
 
 	snd_soc_card_set_drvdata(card, dd);
 	platform_set_drvdata(pdev, card);
@@ -645,16 +651,20 @@
 	ret = atmel_classd_asoc_card_init(dev, card);
 	if (ret) {
 		dev_err(dev, "failed to init sound card\n");
-		return ret;
+		goto unregister_codec;
 	}
 
 	ret = devm_snd_soc_register_card(dev, card);
 	if (ret) {
 		dev_err(dev, "failed to register sound card: %d\n", ret);
-		return ret;
+		goto unregister_codec;
 	}
 
 	return 0;
+
+unregister_codec:
+	snd_soc_unregister_codec(dev);
+	return ret;
 }
 
 static int atmel_classd_remove(struct platform_device *pdev)
diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c
new file mode 100644
index 0000000..aee4787
--- /dev/null
+++ b/sound/soc/atmel/atmel-pdmic.c
@@ -0,0 +1,738 @@
+/* Atmel PDMIC driver
+ *
+ * Copyright (C) 2015 Atmel
+ *
+ * Author: Songjun Wu <songjun.wu@atmel.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 or later
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include "atmel-pdmic.h"
+
+struct atmel_pdmic_pdata {
+	u32 mic_min_freq;
+	u32 mic_max_freq;
+	s32 mic_offset;
+	const char *card_name;
+};
+
+struct atmel_pdmic {
+	dma_addr_t phy_base;
+	struct regmap *regmap;
+	struct clk *pclk;
+	struct clk *gclk;
+	int irq;
+	struct snd_pcm_substream *substream;
+	const struct atmel_pdmic_pdata *pdata;
+};
+
+static const struct of_device_id atmel_pdmic_of_match[] = {
+	{
+		.compatible = "atmel,sama5d2-pdmic",
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(of, atmel_pdmic_of_match);
+
+#define PDMIC_OFFSET_MAX_VAL	S16_MAX
+#define PDMIC_OFFSET_MIN_VAL	S16_MIN
+
+static struct atmel_pdmic_pdata *atmel_pdmic_dt_init(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct atmel_pdmic_pdata *pdata;
+
+	if (!np) {
+		dev_err(dev, "device node not found\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+
+	if (of_property_read_string(np, "atmel,model", &pdata->card_name))
+		pdata->card_name = "PDMIC";
+
+	if (of_property_read_u32(np, "atmel,mic-min-freq",
+				 &pdata->mic_min_freq)) {
+		dev_err(dev, "failed to get mic-min-freq\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (of_property_read_u32(np, "atmel,mic-max-freq",
+				 &pdata->mic_max_freq)) {
+		dev_err(dev, "failed to get mic-max-freq\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (pdata->mic_max_freq < pdata->mic_min_freq) {
+		dev_err(dev,
+			"mic-max-freq should not less than mic-min-freq\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (of_property_read_s32(np, "atmel,mic-offset", &pdata->mic_offset))
+		pdata->mic_offset = 0;
+
+	if (pdata->mic_offset > PDMIC_OFFSET_MAX_VAL) {
+		dev_warn(dev,
+			 "mic-offset value %d is larger than the max value %d, the max value is specified\n",
+			 pdata->mic_offset, PDMIC_OFFSET_MAX_VAL);
+		pdata->mic_offset = PDMIC_OFFSET_MAX_VAL;
+	} else if (pdata->mic_offset < PDMIC_OFFSET_MIN_VAL) {
+		dev_warn(dev,
+			 "mic-offset value %d is less than the min value %d, the min value is specified\n",
+			 pdata->mic_offset, PDMIC_OFFSET_MIN_VAL);
+		pdata->mic_offset = PDMIC_OFFSET_MIN_VAL;
+	}
+
+	return pdata;
+}
+
+/* cpu dai component */
+static int atmel_pdmic_cpu_dai_startup(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *cpu_dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
+	int ret;
+
+	ret = clk_prepare_enable(dd->gclk);
+	if (ret)
+		return ret;
+
+	ret =  clk_prepare_enable(dd->pclk);
+	if (ret)
+		return ret;
+
+	/* Clear all bits in the Control Register(PDMIC_CR) */
+	regmap_write(dd->regmap, PDMIC_CR, 0);
+
+	dd->substream = substream;
+
+	/* Enable the overrun error interrupt */
+	regmap_write(dd->regmap, PDMIC_IER, PDMIC_IER_OVRE);
+
+	return 0;
+}
+
+static void atmel_pdmic_cpu_dai_shutdown(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *cpu_dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
+
+	/* Disable the overrun error interrupt */
+	regmap_write(dd->regmap, PDMIC_IDR, PDMIC_IDR_OVRE);
+
+	clk_disable_unprepare(dd->gclk);
+	clk_disable_unprepare(dd->pclk);
+}
+
+static int atmel_pdmic_cpu_dai_prepare(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *cpu_dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
+	u32 val;
+
+	/* Clean the PDMIC Converted Data Register */
+	return regmap_read(dd->regmap, PDMIC_CDR, &val);
+}
+
+static const struct snd_soc_dai_ops atmel_pdmic_cpu_dai_ops = {
+	.startup	= atmel_pdmic_cpu_dai_startup,
+	.shutdown	= atmel_pdmic_cpu_dai_shutdown,
+	.prepare	= atmel_pdmic_cpu_dai_prepare,
+};
+
+#define ATMEL_PDMIC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver atmel_pdmic_cpu_dai = {
+	.capture = {
+		.channels_min	= 1,
+		.channels_max	= 1,
+		.rates		= SNDRV_PCM_RATE_KNOT,
+		.formats	= ATMEL_PDMIC_FORMATS,},
+	.ops = &atmel_pdmic_cpu_dai_ops,
+};
+
+static const struct snd_soc_component_driver atmel_pdmic_cpu_dai_component = {
+	.name = "atmel-pdmic",
+};
+
+/* platform */
+#define ATMEL_PDMIC_MAX_BUF_SIZE  (64 * 1024)
+#define ATMEL_PDMIC_PREALLOC_BUF_SIZE  ATMEL_PDMIC_MAX_BUF_SIZE
+
+static const struct snd_pcm_hardware atmel_pdmic_hw = {
+	.info			= SNDRV_PCM_INFO_MMAP
+				| SNDRV_PCM_INFO_MMAP_VALID
+				| SNDRV_PCM_INFO_INTERLEAVED
+				| SNDRV_PCM_INFO_RESUME
+				| SNDRV_PCM_INFO_PAUSE,
+	.formats		= ATMEL_PDMIC_FORMATS,
+	.buffer_bytes_max	= ATMEL_PDMIC_MAX_BUF_SIZE,
+	.period_bytes_min	= 256,
+	.period_bytes_max	= 32 * 1024,
+	.periods_min		= 2,
+	.periods_max		= 256,
+};
+
+static int
+atmel_pdmic_platform_configure_dma(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct dma_slave_config *slave_config)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
+	int ret;
+
+	ret = snd_hwparams_to_dma_slave_config(substream, params,
+					       slave_config);
+	if (ret) {
+		dev_err(rtd->platform->dev,
+			"hw params to dma slave configure failed\n");
+		return ret;
+	}
+
+	slave_config->src_addr		= dd->phy_base + PDMIC_CDR;
+	slave_config->src_maxburst	= 1;
+	slave_config->dst_maxburst	= 1;
+
+	return 0;
+}
+
+static const struct snd_dmaengine_pcm_config
+atmel_pdmic_dmaengine_pcm_config = {
+	.prepare_slave_config	= atmel_pdmic_platform_configure_dma,
+	.pcm_hardware		= &atmel_pdmic_hw,
+	.prealloc_buffer_size	= ATMEL_PDMIC_PREALLOC_BUF_SIZE,
+};
+
+/* codec */
+/* Mic Gain = dgain * 2^(-scale) */
+struct mic_gain {
+	unsigned int dgain;
+	unsigned int scale;
+};
+
+/* range from -90 dB to 90 dB */
+static const struct mic_gain mic_gain_table[] = {
+{    1, 15}, {    1, 14},                           /* -90, -84 dB */
+{    3, 15}, {    1, 13}, {    3, 14}, {    1, 12}, /* -81, -78, -75, -72 dB */
+{    5, 14}, {   13, 15},                           /* -70, -68 dB */
+{    9, 14}, {   21, 15}, {   23, 15}, {   13, 14}, /* -65 ~ -62 dB */
+{   29, 15}, {   33, 15}, {   37, 15}, {   41, 15}, /* -61 ~ -58 dB */
+{   23, 14}, {   13, 13}, {   58, 15}, {   65, 15}, /* -57 ~ -54 dB */
+{   73, 15}, {   41, 14}, {   23, 13}, {   13, 12}, /* -53 ~ -50 dB */
+{   29, 13}, {   65, 14}, {   73, 14}, {   41, 13}, /* -49 ~ -46 dB */
+{   23, 12}, {  207, 15}, {   29, 12}, {   65, 13}, /* -45 ~ -42 dB */
+{   73, 13}, {   41, 12}, {   23, 11}, {  413, 15}, /* -41 ~ -38 dB */
+{  463, 15}, {  519, 15}, {  583, 15}, {  327, 14}, /* -37 ~ -34 dB */
+{  367, 14}, {  823, 15}, {  231, 13}, { 1036, 15}, /* -33 ~ -30 dB */
+{ 1163, 15}, { 1305, 15}, {  183, 12}, { 1642, 15}, /* -29 ~ -26 dB */
+{ 1843, 15}, { 2068, 15}, {  145, 11}, { 2603, 15}, /* -25 ~ -22 dB */
+{  365, 12}, { 3277, 15}, { 3677, 15}, { 4125, 15}, /* -21 ~ -18 dB */
+{ 4629, 15}, { 5193, 15}, { 5827, 15}, { 3269, 14}, /* -17 ~ -14 dB */
+{  917, 12}, { 8231, 15}, { 9235, 15}, { 5181, 14}, /* -13 ~ -10 dB */
+{11627, 15}, {13045, 15}, {14637, 15}, {16423, 15}, /*  -9 ~ -6 dB */
+{18427, 15}, {20675, 15}, { 5799, 13}, {26029, 15}, /*  -5 ~ -2 dB */
+{ 7301, 13}, {    1,  0}, {18383, 14}, {10313, 13}, /*  -1 ~ 2 dB */
+{23143, 14}, {25967, 14}, {29135, 14}, {16345, 13}, /*   3 ~ 6 dB */
+{ 4585, 11}, {20577, 13}, { 1443,  9}, {25905, 13}, /*   7 ~ 10 dB */
+{14533, 12}, { 8153, 11}, { 2287,  9}, {20529, 12}, /*  11 ~ 14 dB */
+{11517, 11}, { 6461, 10}, {28997, 12}, { 4067,  9}, /*  15 ~ 18 dB */
+{18253, 11}, {   10,  0}, {22979, 11}, {25783, 11}, /*  19 ~ 22 dB */
+{28929, 11}, {32459, 11}, { 9105,  9}, {20431, 10}, /*  23 ~ 26 dB */
+{22925, 10}, {12861,  9}, { 7215,  8}, {16191,  9}, /*  27 ~ 30 dB */
+{ 9083,  8}, {20383,  9}, {11435,  8}, { 6145,  7}, /*  31 ~ 34 dB */
+{ 3599,  6}, {32305,  9}, {18123,  8}, {20335,  8}, /*  35 ~ 38 dB */
+{  713,  3}, {  100,  0}, { 7181,  6}, { 8057,  6}, /*  39 ~ 42 dB */
+{  565,  2}, {20287,  7}, {11381,  6}, {25539,  7}, /*  43 ~ 46 dB */
+{ 1791,  3}, { 4019,  4}, { 9019,  5}, {20239,  6}, /*  47 ~ 50 dB */
+{ 5677,  4}, {25479,  6}, { 7147,  4}, { 8019,  4}, /*  51 ~ 54 dB */
+{17995,  5}, {20191,  5}, {11327,  4}, {12709,  4}, /*  55 ~ 58 dB */
+{ 3565,  2}, { 1000,  0}, { 1122,  0}, { 1259,  0}, /*  59 ~ 62 dB */
+{ 2825,  1}, {12679,  3}, { 7113,  2}, { 7981,  2}, /*  63 ~ 66 dB */
+{ 8955,  2}, {20095,  3}, {22547,  3}, {12649,  2}, /*  67 ~ 70 dB */
+{28385,  3}, { 3981,  0}, {17867,  2}, {20047,  2}, /*  71 ~ 74 dB */
+{11247,  1}, {12619,  1}, {14159,  1}, {31773,  2}, /*  75 ~ 78 dB */
+{17825,  1}, {10000,  0}, {11220,  0}, {12589,  0}, /*  79 ~ 82 dB */
+{28251,  1}, {15849,  0}, {17783,  0}, {19953,  0}, /*  83 ~ 86 dB */
+{22387,  0}, {25119,  0}, {28184,  0}, {31623,  0}, /*  87 ~ 90 dB */
+};
+
+static const DECLARE_TLV_DB_RANGE(mic_gain_tlv,
+	0, 1, TLV_DB_SCALE_ITEM(-9000, 600, 0),
+	2, 5, TLV_DB_SCALE_ITEM(-8100, 300, 0),
+	6, 7, TLV_DB_SCALE_ITEM(-7000, 200, 0),
+	8, ARRAY_SIZE(mic_gain_table)-1, TLV_DB_SCALE_ITEM(-6500, 100, 0),
+);
+
+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);
+	unsigned int dgain_val, scale_val;
+	int i;
+
+	dgain_val = (snd_soc_read(codec, PDMIC_DSPR1) & PDMIC_DSPR1_DGAIN_MASK)
+		    >> PDMIC_DSPR1_DGAIN_SHIFT;
+
+	scale_val = (snd_soc_read(codec, PDMIC_DSPR0) & PDMIC_DSPR0_SCALE_MASK)
+		    >> PDMIC_DSPR0_SCALE_SHIFT;
+
+	for (i = 0; i < ARRAY_SIZE(mic_gain_table); i++) {
+		if ((mic_gain_table[i].dgain == dgain_val) &&
+		    (mic_gain_table[i].scale == scale_val))
+			ucontrol->value.integer.value[0] = i;
+	}
+
+	return 0;
+}
+
+static int pdmic_put_mic_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int max = mc->max;
+	unsigned int val;
+	int ret;
+
+	val = ucontrol->value.integer.value[0];
+
+	if (val > max)
+		return -EINVAL;
+
+	ret = snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_MASK,
+			 mic_gain_table[val].dgain << PDMIC_DSPR1_DGAIN_SHIFT);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_update_bits(codec, PDMIC_DSPR0, PDMIC_DSPR0_SCALE_MASK,
+			 mic_gain_table[val].scale << PDMIC_DSPR0_SCALE_SHIFT);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new atmel_pdmic_snd_controls[] = {
+SOC_SINGLE_EXT_TLV("Mic Capture Volume", PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_SHIFT,
+		   ARRAY_SIZE(mic_gain_table)-1, 0,
+		   pdmic_get_mic_volsw, pdmic_put_mic_volsw, mic_gain_tlv),
+
+SOC_SINGLE("High Pass Filter Switch", PDMIC_DSPR0,
+	   PDMIC_DSPR0_HPFBYP_SHIFT, 1, 1),
+
+SOC_SINGLE("SINCC Filter Switch", PDMIC_DSPR0, PDMIC_DSPR0_SINBYP_SHIFT, 1, 1),
+};
+
+static int atmel_pdmic_codec_probe(struct snd_soc_codec *codec)
+{
+	struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec);
+	struct atmel_pdmic *dd = snd_soc_card_get_drvdata(card);
+
+	snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_OFFSET_MASK,
+		     (u32)(dd->pdata->mic_offset << PDMIC_DSPR1_OFFSET_SHIFT));
+
+	return 0;
+}
+
+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),
+};
+
+/* codec dai component */
+#define PDMIC_MR_PRESCAL_MAX_VAL 127
+
+static int
+atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *codec_dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_codec *codec = codec_dai->codec;
+	unsigned int rate_min = substream->runtime->hw.rate_min;
+	unsigned int rate_max = substream->runtime->hw.rate_max;
+	int fs = params_rate(params);
+	int bits = params_width(params);
+	unsigned long pclk_rate, gclk_rate;
+	unsigned int f_pdmic;
+	u32 mr_val, dspr0_val, pclk_prescal, gclk_prescal;
+
+	if (params_channels(params) != 1) {
+		dev_err(codec->dev,
+			"only supports one channel\n");
+		return -EINVAL;
+	}
+
+	if ((fs < rate_min) || (fs > rate_max)) {
+		dev_err(codec->dev,
+			"sample rate is %dHz, min rate is %dHz, max rate is %dHz\n",
+			fs, rate_min, rate_max);
+
+		return -EINVAL;
+	}
+
+	switch (bits) {
+	case 16:
+		dspr0_val = (PDMIC_DSPR0_SIZE_16_BITS
+			     << PDMIC_DSPR0_SIZE_SHIFT);
+		break;
+	case 32:
+		dspr0_val = (PDMIC_DSPR0_SIZE_32_BITS
+			     << PDMIC_DSPR0_SIZE_SHIFT);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if ((fs << 7) > (rate_max << 6)) {
+		f_pdmic = fs << 6;
+		dspr0_val |= PDMIC_DSPR0_OSR_64 << PDMIC_DSPR0_OSR_SHIFT;
+	} else {
+		f_pdmic = fs << 7;
+		dspr0_val |= PDMIC_DSPR0_OSR_128 << PDMIC_DSPR0_OSR_SHIFT;
+	}
+
+	pclk_rate = clk_get_rate(dd->pclk);
+	gclk_rate = clk_get_rate(dd->gclk);
+
+	/* PRESCAL = SELCK/(2*f_pdmic) - 1*/
+	pclk_prescal = (u32)(pclk_rate/(f_pdmic << 1)) - 1;
+	gclk_prescal = (u32)(gclk_rate/(f_pdmic << 1)) - 1;
+
+	if ((pclk_prescal > PDMIC_MR_PRESCAL_MAX_VAL) ||
+	    (gclk_rate/((gclk_prescal + 1) << 1) <
+	     pclk_rate/((pclk_prescal + 1) << 1))) {
+		mr_val = gclk_prescal << PDMIC_MR_PRESCAL_SHIFT;
+		mr_val |= PDMIC_MR_CLKS_GCK << PDMIC_MR_CLKS_SHIFT;
+	} else {
+		mr_val = pclk_prescal << PDMIC_MR_PRESCAL_SHIFT;
+		mr_val |= PDMIC_MR_CLKS_PCK << PDMIC_MR_CLKS_SHIFT;
+	}
+
+	snd_soc_update_bits(codec, PDMIC_MR,
+		PDMIC_MR_PRESCAL_MASK | PDMIC_MR_CLKS_MASK, mr_val);
+
+	snd_soc_update_bits(codec, PDMIC_DSPR0,
+		PDMIC_DSPR0_OSR_MASK | PDMIC_DSPR0_SIZE_MASK, dspr0_val);
+
+	return 0;
+}
+
+static int atmel_pdmic_codec_dai_prepare(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *codec_dai)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+
+	snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK,
+			    PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT);
+
+	return 0;
+}
+
+static int atmel_pdmic_codec_dai_trigger(struct snd_pcm_substream *substream,
+					int cmd, struct snd_soc_dai *codec_dai)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u32 val;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		val = PDMIC_CR_ENPDM_EN << PDMIC_CR_ENPDM_SHIFT;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		val = PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK, val);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops atmel_pdmic_codec_dai_ops = {
+	.hw_params	= atmel_pdmic_codec_dai_hw_params,
+	.prepare	= atmel_pdmic_codec_dai_prepare,
+	.trigger	= atmel_pdmic_codec_dai_trigger,
+};
+
+#define ATMEL_PDMIC_CODEC_DAI_NAME  "atmel-pdmic-hifi"
+
+static struct snd_soc_dai_driver atmel_pdmic_codec_dai = {
+	.name = ATMEL_PDMIC_CODEC_DAI_NAME,
+	.capture = {
+		.stream_name	= "Capture",
+		.channels_min	= 1,
+		.channels_max	= 1,
+		.rates		= SNDRV_PCM_RATE_KNOT,
+		.formats	= ATMEL_PDMIC_FORMATS,
+	},
+	.ops = &atmel_pdmic_codec_dai_ops,
+};
+
+/* ASoC sound card */
+static int atmel_pdmic_asoc_card_init(struct device *dev,
+				struct snd_soc_card *card)
+{
+	struct snd_soc_dai_link *dai_link;
+	struct atmel_pdmic *dd = snd_soc_card_get_drvdata(card);
+
+	dai_link = devm_kzalloc(dev, sizeof(*dai_link), GFP_KERNEL);
+	if (!dai_link)
+		return -ENOMEM;
+
+	dai_link->name			= "PDMIC";
+	dai_link->stream_name		= "PDMIC PCM";
+	dai_link->codec_dai_name	= ATMEL_PDMIC_CODEC_DAI_NAME;
+	dai_link->cpu_dai_name		= dev_name(dev);
+	dai_link->codec_name		= dev_name(dev);
+	dai_link->platform_name		= dev_name(dev);
+
+	card->dai_link	= dai_link;
+	card->num_links	= 1;
+	card->name	= dd->pdata->card_name;
+	card->dev	= dev;
+
+	return 0;
+}
+
+static void atmel_pdmic_get_sample_rate(struct atmel_pdmic *dd,
+	unsigned int *rate_min, unsigned int *rate_max)
+{
+	u32 mic_min_freq = dd->pdata->mic_min_freq;
+	u32 mic_max_freq = dd->pdata->mic_max_freq;
+	u32 clk_max_rate = (u32)(clk_get_rate(dd->pclk) >> 1);
+	u32 clk_min_rate = (u32)(clk_get_rate(dd->gclk) >> 8);
+
+	if (mic_max_freq > clk_max_rate)
+		mic_max_freq = clk_max_rate;
+
+	if (mic_min_freq < clk_min_rate)
+		mic_min_freq = clk_min_rate;
+
+	*rate_min = DIV_ROUND_CLOSEST(mic_min_freq, 128);
+	*rate_max = mic_max_freq >> 6;
+}
+
+/* PDMIC interrupt handler */
+static irqreturn_t atmel_pdmic_interrupt(int irq, void *dev_id)
+{
+	struct atmel_pdmic *dd = (struct atmel_pdmic *)dev_id;
+	u32 pdmic_isr;
+	irqreturn_t ret = IRQ_NONE;
+
+	regmap_read(dd->regmap, PDMIC_ISR, &pdmic_isr);
+
+	if (pdmic_isr & PDMIC_ISR_OVRE) {
+		regmap_update_bits(dd->regmap, PDMIC_CR, PDMIC_CR_ENPDM_MASK,
+				   PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT);
+
+		snd_pcm_stop_xrun(dd->substream);
+
+		ret = IRQ_HANDLED;
+	}
+
+	return ret;
+}
+
+/* regmap configuration */
+#define ATMEL_PDMIC_REG_MAX    0x124
+static const struct regmap_config atmel_pdmic_regmap_config = {
+	.reg_bits	= 32,
+	.reg_stride	= 4,
+	.val_bits	= 32,
+	.max_register	= ATMEL_PDMIC_REG_MAX,
+};
+
+static int atmel_pdmic_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct atmel_pdmic *dd;
+	struct resource *res;
+	void __iomem *io_base;
+	const struct atmel_pdmic_pdata *pdata;
+	struct snd_soc_card *card;
+	unsigned int rate_min, rate_max;
+	int ret;
+
+	pdata = atmel_pdmic_dt_init(dev);
+	if (IS_ERR(pdata))
+		return PTR_ERR(pdata);
+
+	dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL);
+	if (!dd)
+		return -ENOMEM;
+
+	dd->pdata = pdata;
+
+	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);
+		return ret;
+	}
+
+	dd->pclk = devm_clk_get(dev, "pclk");
+	if (IS_ERR(dd->pclk)) {
+		ret = PTR_ERR(dd->pclk);
+		dev_err(dev, "failed to get peripheral clock: %d\n", ret);
+		return ret;
+	}
+
+	dd->gclk = devm_clk_get(dev, "gclk");
+	if (IS_ERR(dd->gclk)) {
+		ret = PTR_ERR(dd->gclk);
+		dev_err(dev, "failed to get GCK: %d\n", ret);
+		return ret;
+	}
+
+	/* The gclk clock frequency must always be tree times
+	 * lower than the pclk clock frequency
+	 */
+	ret = clk_set_rate(dd->gclk, clk_get_rate(dd->pclk)/3);
+	if (ret) {
+		dev_err(dev, "failed to set GCK clock rate: %d\n", ret);
+		return ret;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "no memory resource\n");
+		return -ENXIO;
+	}
+
+	io_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(io_base)) {
+		ret = PTR_ERR(io_base);
+		dev_err(dev, "failed to remap register memory: %d\n", ret);
+		return ret;
+	}
+
+	dd->phy_base = res->start;
+
+	dd->regmap = devm_regmap_init_mmio(dev, io_base,
+					   &atmel_pdmic_regmap_config);
+	if (IS_ERR(dd->regmap)) {
+		ret = PTR_ERR(dd->regmap);
+		dev_err(dev, "failed to init register map: %d\n", ret);
+		return ret;
+	}
+
+	ret =  devm_request_irq(dev, dd->irq, atmel_pdmic_interrupt, 0,
+				"PDMIC", (void *)dd);
+	if (ret < 0) {
+		dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
+			dd->irq, ret);
+		return ret;
+	}
+
+	/* Get the minimal and maximal sample rate that micphone supports */
+	atmel_pdmic_get_sample_rate(dd, &rate_min, &rate_max);
+
+	/* register cpu dai */
+	atmel_pdmic_cpu_dai.capture.rate_min = rate_min;
+	atmel_pdmic_cpu_dai.capture.rate_max = rate_max;
+	ret = devm_snd_soc_register_component(dev,
+					      &atmel_pdmic_cpu_dai_component,
+					      &atmel_pdmic_cpu_dai, 1);
+	if (ret) {
+		dev_err(dev, "could not register CPU DAI: %d\n", ret);
+		return ret;
+	}
+
+	/* register platform */
+	ret = devm_snd_dmaengine_pcm_register(dev,
+					     &atmel_pdmic_dmaengine_pcm_config,
+					     0);
+	if (ret) {
+		dev_err(dev, "could not register platform: %d\n", ret);
+		return ret;
+	}
+
+	/* register codec and codec dai */
+	atmel_pdmic_codec_dai.capture.rate_min = rate_min;
+	atmel_pdmic_codec_dai.capture.rate_max = rate_max;
+	ret = snd_soc_register_codec(dev, &soc_codec_dev_pdmic,
+				     &atmel_pdmic_codec_dai, 1);
+	if (ret) {
+		dev_err(dev, "could not register codec: %d\n", ret);
+		return ret;
+	}
+
+	/* register sound card */
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!card) {
+		ret = -ENOMEM;
+		goto unregister_codec;
+	}
+
+	snd_soc_card_set_drvdata(card, dd);
+	platform_set_drvdata(pdev, card);
+
+	ret = atmel_pdmic_asoc_card_init(dev, card);
+	if (ret) {
+		dev_err(dev, "failed to init sound card: %d\n", ret);
+		goto unregister_codec;
+	}
+
+	ret = devm_snd_soc_register_card(dev, card);
+	if (ret) {
+		dev_err(dev, "failed to register sound card: %d\n", ret);
+		goto unregister_codec;
+	}
+
+	return 0;
+
+unregister_codec:
+	snd_soc_unregister_codec(dev);
+	return ret;
+}
+
+static int atmel_pdmic_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver atmel_pdmic_driver = {
+	.driver	= {
+		.name		= "atmel-pdmic",
+		.of_match_table	= of_match_ptr(atmel_pdmic_of_match),
+		.pm		= &snd_soc_pm_ops,
+	},
+	.probe	= atmel_pdmic_probe,
+	.remove	= atmel_pdmic_remove,
+};
+module_platform_driver(atmel_pdmic_driver);
+
+MODULE_DESCRIPTION("Atmel PDMIC driver under ALSA SoC architecture");
+MODULE_AUTHOR("Songjun Wu <songjun.wu@atmel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/atmel/atmel-pdmic.h b/sound/soc/atmel/atmel-pdmic.h
new file mode 100644
index 0000000..4527ac7
--- /dev/null
+++ b/sound/soc/atmel/atmel-pdmic.h
@@ -0,0 +1,80 @@
+#ifndef __ATMEL_PDMIC_H_
+#define __ATMEL_PDMIC_H_
+
+#include <linux/bitops.h>
+
+#define PDMIC_CR	0x00000000
+
+#define PDMIC_CR_SWRST		0x1
+#define PDMIC_CR_SWRST_MASK	BIT(0)
+#define PDMIC_CR_SWRST_SHIFT	(0)
+
+#define PDMIC_CR_ENPDM_DIS	0x0
+#define PDMIC_CR_ENPDM_EN	0x1
+#define PDMIC_CR_ENPDM_MASK	BIT(4)
+#define PDMIC_CR_ENPDM_SHIFT	(4)
+
+#define PDMIC_MR	0x00000004
+
+#define PDMIC_MR_CLKS_PCK	0x0
+#define PDMIC_MR_CLKS_GCK	0x1
+#define PDMIC_MR_CLKS_MASK	BIT(4)
+#define PDMIC_MR_CLKS_SHIFT	(4)
+
+#define PDMIC_MR_PRESCAL_MASK	GENMASK(14, 8)
+#define PDMIC_MR_PRESCAL_SHIFT	(8)
+
+#define PDMIC_CDR	0x00000014
+
+#define PDMIC_IER	0x00000018
+#define PDMIC_IER_OVRE			BIT(25)
+
+#define PDMIC_IDR	0x0000001c
+#define PDMIC_IDR_OVRE			BIT(25)
+
+#define PDMIC_IMR	0x00000020
+
+#define PDMIC_ISR	0x00000024
+#define PDMIC_ISR_OVRE			BIT(25)
+
+#define PDMIC_DSPR0	0x00000058
+
+#define PDMIC_DSPR0_HPFBYP_DIS		0x1
+#define PDMIC_DSPR0_HPFBYP_EN		0x0
+#define PDMIC_DSPR0_HPFBYP_MASK		BIT(1)
+#define PDMIC_DSPR0_HPFBYP_SHIFT	(1)
+
+#define PDMIC_DSPR0_SINBYP_DIS		0x1
+#define PDMIC_DSPR0_SINBYP_EN		0x0
+#define PDMIC_DSPR0_SINBYP_MASK		BIT(2)
+#define PDMIC_DSPR0_SINBYP_SHIFT	(2)
+
+#define PDMIC_DSPR0_SIZE_16_BITS	0x0
+#define PDMIC_DSPR0_SIZE_32_BITS	0x1
+#define PDMIC_DSPR0_SIZE_MASK		BIT(3)
+#define PDMIC_DSPR0_SIZE_SHIFT		(3)
+
+#define PDMIC_DSPR0_OSR_128		0x0
+#define PDMIC_DSPR0_OSR_64		0x1
+#define PDMIC_DSPR0_OSR_MASK		GENMASK(6, 4)
+#define PDMIC_DSPR0_OSR_SHIFT		(4)
+
+#define PDMIC_DSPR0_SCALE_MASK		GENMASK(11, 8)
+#define PDMIC_DSPR0_SCALE_SHIFT		(8)
+
+#define PDMIC_DSPR0_SHIFT_MASK		GENMASK(15, 12)
+#define PDMIC_DSPR0_SHIFT_SHIFT		(12)
+
+#define PDMIC_DSPR1	0x0000005c
+
+#define PDMIC_DSPR1_DGAIN_MASK		GENMASK(14, 0)
+#define PDMIC_DSPR1_DGAIN_SHIFT		(0)
+
+#define PDMIC_DSPR1_OFFSET_MASK		GENMASK(31, 16)
+#define PDMIC_DSPR1_OFFSET_SHIFT	(16)
+
+#define PDMIC_WPMR	0x000000e4
+
+#define PDMIC_WPSR	0x000000e8
+
+#endif
diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c
index 1933bcd..fdd28ed 100644
--- a/sound/soc/atmel/atmel_wm8904.c
+++ b/sound/soc/atmel/atmel_wm8904.c
@@ -183,6 +183,7 @@
 	.driver = {
 		.name = "atmel-wm8904-audio",
 		.of_match_table = of_match_ptr(atmel_asoc_wm8904_dt_ids),
+		.pm		= &snd_soc_pm_ops,
 	},
 	.probe = atmel_asoc_wm8904_probe,
 	.remove = atmel_asoc_wm8904_remove,
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
index 8c435be..3303d5f 100644
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -31,20 +31,20 @@
  * General Public License for more details.
  */
 
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/slab.h>
 
 #include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/dmaengine_pcm.h>
 
 /* Clock registers */
 #define BCM2835_CLK_PCMCTL_REG  0x00
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index cfdafc4..50693c8 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -55,9 +55,11 @@
 	select SND_SOC_CS4271_SPI if SPI_MASTER
 	select SND_SOC_CS42XX8_I2C if I2C
 	select SND_SOC_CS4349 if I2C
+	select SND_SOC_CS47L24 if MFD_CS47L24
 	select SND_SOC_CX20442 if TTY
 	select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_DA7213 if I2C
+	select SND_SOC_DA7218 if I2C
 	select SND_SOC_DA7219 if I2C
 	select SND_SOC_DA732X if I2C
 	select SND_SOC_DA9055 if I2C
@@ -66,7 +68,9 @@
 	select SND_SOC_ES8328_SPI if SPI_MASTER
 	select SND_SOC_ES8328_I2C if I2C
 	select SND_SOC_GTM601
+	select SND_SOC_HDAC_HDMI
 	select SND_SOC_ICS43432
+	select SND_SOC_INNO_RK3036
 	select SND_SOC_ISABELLE if I2C
 	select SND_SOC_JZ4740_CODEC
 	select SND_SOC_LM4857 if I2C
@@ -83,16 +87,20 @@
 	select SND_SOC_ML26124 if I2C
 	select SND_SOC_NAU8825 if I2C
 	select SND_SOC_PCM1681 if I2C
-	select SND_SOC_PCM1792A if SPI_MASTER
+	select SND_SOC_PCM179X if SPI_MASTER
 	select SND_SOC_PCM3008
+	select SND_SOC_PCM3168A_I2C if I2C
+	select SND_SOC_PCM3168A_SPI if SPI_MASTER
 	select SND_SOC_PCM512x_I2C if I2C
 	select SND_SOC_PCM512x_SPI if SPI_MASTER
 	select SND_SOC_RT286 if I2C
 	select SND_SOC_RT298 if I2C
+	select SND_SOC_RT5616 if I2C
 	select SND_SOC_RT5631 if I2C
 	select SND_SOC_RT5640 if I2C
 	select SND_SOC_RT5645 if I2C
 	select SND_SOC_RT5651 if I2C
+	select SND_SOC_RT5659 if I2C
 	select SND_SOC_RT5670 if I2C
 	select SND_SOC_RT5677 if I2C && SPI_MASTER
 	select SND_SOC_SGTL5000 if I2C
@@ -195,10 +203,12 @@
 
 config SND_SOC_ARIZONA
 	tristate
+	default y if SND_SOC_CS47L24=y
 	default y if SND_SOC_WM5102=y
 	default y if SND_SOC_WM5110=y
 	default y if SND_SOC_WM8997=y
 	default y if SND_SOC_WM8998=y
+	default m if SND_SOC_CS47L24=m
 	default m if SND_SOC_WM5102=m
 	default m if SND_SOC_WM5110=m
 	default m if SND_SOC_WM8997=m
@@ -211,9 +221,12 @@
 
 config SND_SOC_WM_ADSP
 	tristate
+	select SND_SOC_COMPRESS
+	default y if SND_SOC_CS47L24=y
 	default y if SND_SOC_WM5102=y
 	default y if SND_SOC_WM5110=y
 	default y if SND_SOC_WM2200=y
+	default m if SND_SOC_CS47L24=m
 	default m if SND_SOC_WM5102=m
 	default m if SND_SOC_WM5110=m
 	default m if SND_SOC_WM2200=m
@@ -422,6 +435,9 @@
 	tristate "Cirrus Logic CS4349 CODEC"
 	depends on I2C
 
+config SND_SOC_CS47L24
+	tristate
+
 config SND_SOC_CX20442
 	tristate
 	depends on TTY
@@ -439,6 +455,9 @@
 config SND_SOC_DA7213
         tristate
 
+config SND_SOC_DA7218
+	tristate
+
 config SND_SOC_DA7219
         tristate
 
@@ -468,9 +487,17 @@
 config SND_SOC_GTM601
 	tristate 'GTM601 UMTS modem audio codec'
 
+config SND_SOC_HDAC_HDMI
+	tristate
+	select SND_HDA_EXT_CORE
+	select HDMI
+
 config SND_SOC_ICS43432
 	tristate
 
+config SND_SOC_INNO_RK3036
+	tristate "Inno codec driver for RK3036 SoC"
+
 config SND_SOC_ISABELLE
         tristate
 
@@ -499,13 +526,28 @@
 	tristate "Texas Instruments PCM1681 CODEC"
 	depends on I2C
 
-config SND_SOC_PCM1792A
-	tristate "Texas Instruments PCM1792A CODEC"
+config SND_SOC_PCM179X
+	tristate "Texas Instruments PCM179X CODEC"
 	depends on SPI_MASTER
 
 config SND_SOC_PCM3008
        tristate
 
+config SND_SOC_PCM3168A
+	tristate
+
+config SND_SOC_PCM3168A_I2C
+	tristate "Texas Instruments PCM3168A CODEC - I2C"
+	depends on I2C
+	select SND_SOC_PCM3168A
+	select REGMAP_I2C
+
+config SND_SOC_PCM3168A_SPI
+	tristate "Texas Instruments PCM3168A CODEC - SPI"
+	depends on SPI_MASTER
+	select SND_SOC_PCM3168A
+	select REGMAP_SPI
+
 config SND_SOC_PCM512x
 	tristate
 
@@ -523,14 +565,18 @@
 
 config SND_SOC_RL6231
 	tristate
+	default y if SND_SOC_RT5616=y
 	default y if SND_SOC_RT5640=y
 	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_RT5670=y
 	default y if SND_SOC_RT5677=y
+	default m if SND_SOC_RT5616=m
 	default m if SND_SOC_RT5640=m
 	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_RT5670=m
 	default m if SND_SOC_RT5677=m
 
@@ -549,6 +595,9 @@
 	tristate
 	depends on I2C
 
+config SND_SOC_RT5616
+	tristate
+
 config SND_SOC_RT5631
 	tristate "Realtek ALC5631/RT5631 CODEC"
 	depends on I2C
@@ -562,6 +611,9 @@
 config SND_SOC_RT5651
 	tristate
 
+config SND_SOC_RT5659
+	tristate
+
 config SND_SOC_RT5670
 	tristate
 
@@ -838,7 +890,8 @@
 	tristate
 
 config SND_SOC_WM8974
-	tristate
+	tristate "Wolfson Microelectronics WM8974 codec"
+	depends on I2C
 
 config SND_SOC_WM8978
 	tristate "Wolfson Microelectronics WM8978 codec"
@@ -891,6 +944,7 @@
 
 config SND_SOC_WM9713
 	tristate
+	select REGMAP_AC97
 
 # Amp
 config SND_SOC_LM4857
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f632fc4..d44f7d3 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -47,9 +47,11 @@
 snd-soc-cs42xx8-objs := cs42xx8.o
 snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
 snd-soc-cs4349-objs := cs4349.o
+snd-soc-cs47l24-objs := cs47l24.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
 snd-soc-da7213-objs := da7213.o
+snd-soc-da7218-objs := da7218.o
 snd-soc-da7219-objs := da7219.o da7219-aad.o
 snd-soc-da732x-objs := da732x.o
 snd-soc-da9055-objs := da9055.o
@@ -59,7 +61,9 @@
 snd-soc-es8328-i2c-objs := es8328-i2c.o
 snd-soc-es8328-spi-objs := es8328-spi.o
 snd-soc-gtm601-objs := gtm601.o
+snd-soc-hdac-hdmi-objs := hdac_hdmi.o
 snd-soc-ics43432-objs := ics43432.o
+snd-soc-inno-rk3036-objs := inno_rk3036.o
 snd-soc-isabelle-objs := isabelle.o
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-l3-objs := l3.o
@@ -76,8 +80,11 @@
 snd-soc-ml26124-objs := ml26124.o
 snd-soc-nau8825-objs := nau8825.o
 snd-soc-pcm1681-objs := pcm1681.o
-snd-soc-pcm1792a-codec-objs := pcm1792a.o
+snd-soc-pcm179x-codec-objs := pcm179x.o
 snd-soc-pcm3008-objs := pcm3008.o
+snd-soc-pcm3168a-objs := pcm3168a.o
+snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o
+snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o
 snd-soc-pcm512x-objs := pcm512x.o
 snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
 snd-soc-pcm512x-spi-objs := pcm512x-spi.o
@@ -85,10 +92,12 @@
 snd-soc-rl6347a-objs := rl6347a.o
 snd-soc-rt286-objs := rt286.o
 snd-soc-rt298-objs := rt298.o
+snd-soc-rt5616-objs := rt5616.o
 snd-soc-rt5631-objs := rt5631.o
 snd-soc-rt5640-objs := rt5640.o
 snd-soc-rt5645-objs := rt5645.o
 snd-soc-rt5651-objs := rt5651.o
+snd-soc-rt5659-objs := rt5659.o
 snd-soc-rt5670-objs := rt5670.o
 snd-soc-rt5677-objs := rt5677.o
 snd-soc-rt5677-spi-objs := rt5677-spi.o
@@ -242,9 +251,11 @@
 obj-$(CONFIG_SND_SOC_CS42XX8)	+= snd-soc-cs42xx8.o
 obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
 obj-$(CONFIG_SND_SOC_CS4349)	+= snd-soc-cs4349.o
+obj-$(CONFIG_SND_SOC_CS47L24)	+= snd-soc-cs47l24.o
 obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_DA7213)	+= snd-soc-da7213.o
+obj-$(CONFIG_SND_SOC_DA7218)	+= snd-soc-da7218.o
 obj-$(CONFIG_SND_SOC_DA7219)	+= snd-soc-da7219.o
 obj-$(CONFIG_SND_SOC_DA732X)	+= snd-soc-da732x.o
 obj-$(CONFIG_SND_SOC_DA9055)	+= snd-soc-da9055.o
@@ -254,7 +265,9 @@
 obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
 obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
 obj-$(CONFIG_SND_SOC_GTM601)    += snd-soc-gtm601.o
+obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o
 obj-$(CONFIG_SND_SOC_ICS43432)	+= snd-soc-ics43432.o
+obj-$(CONFIG_SND_SOC_INNO_RK3036)	+= snd-soc-inno-rk3036.o
 obj-$(CONFIG_SND_SOC_ISABELLE)	+= snd-soc-isabelle.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
@@ -271,8 +284,11 @@
 obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o
 obj-$(CONFIG_SND_SOC_NAU8825)   += snd-soc-nau8825.o
 obj-$(CONFIG_SND_SOC_PCM1681)	+= snd-soc-pcm1681.o
-obj-$(CONFIG_SND_SOC_PCM1792A)	+= snd-soc-pcm1792a-codec.o
+obj-$(CONFIG_SND_SOC_PCM179X)	+= snd-soc-pcm179x-codec.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
+obj-$(CONFIG_SND_SOC_PCM3168A)	+= snd-soc-pcm3168a.o
+obj-$(CONFIG_SND_SOC_PCM3168A_I2C)	+= snd-soc-pcm3168a-i2c.o
+obj-$(CONFIG_SND_SOC_PCM3168A_SPI)	+= snd-soc-pcm3168a-spi.o
 obj-$(CONFIG_SND_SOC_PCM512x)	+= snd-soc-pcm512x.o
 obj-$(CONFIG_SND_SOC_PCM512x_I2C)	+= snd-soc-pcm512x-i2c.o
 obj-$(CONFIG_SND_SOC_PCM512x_SPI)	+= snd-soc-pcm512x-spi.o
@@ -280,10 +296,12 @@
 obj-$(CONFIG_SND_SOC_RL6347A)	+= snd-soc-rl6347a.o
 obj-$(CONFIG_SND_SOC_RT286)	+= snd-soc-rt286.o
 obj-$(CONFIG_SND_SOC_RT298)	+= snd-soc-rt298.o
+obj-$(CONFIG_SND_SOC_RT5616)	+= snd-soc-rt5616.o
 obj-$(CONFIG_SND_SOC_RT5631)	+= snd-soc-rt5631.o
 obj-$(CONFIG_SND_SOC_RT5640)	+= snd-soc-rt5640.o
 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_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/ak4613.c b/sound/soc/codecs/ak4613.c
index 07a2664..647f69d 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -70,18 +70,11 @@
 #define FMT_MASK	(0xf8)
 
 /* CTRL2 */
+#define DFS_MASK		(3 << 2)
 #define DFS_NORMAL_SPEED	(0 << 2)
 #define DFS_DOUBLE_SPEED	(1 << 2)
 #define DFS_QUAD_SPEED		(2 << 2)
 
-struct ak4613_priv {
-	struct mutex lock;
-
-	unsigned int fmt;
-	u8 fmt_ctrl;
-	int cnt;
-};
-
 struct ak4613_formats {
 	unsigned int width;
 	unsigned int fmt;
@@ -92,6 +85,16 @@
 	struct ak4613_formats playback;
 };
 
+struct ak4613_priv {
+	struct mutex lock;
+	const struct ak4613_interface *iface;
+
+	unsigned int fmt;
+	u8 oc;
+	u8 ic;
+	int cnt;
+};
+
 /*
  * Playback Volume
  *
@@ -126,7 +129,7 @@
 	{ 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0x00 },
 };
 
-#define AUDIO_IFACE_IDX_TO_VAL(i) (i << 3)
+#define AUDIO_IFACE_TO_VAL(fmts) ((fmts - ak4613_iface) << 3)
 #define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt }
 static const struct ak4613_interface ak4613_iface[] = {
 	/* capture */				/* playback */
@@ -240,7 +243,7 @@
 		priv->cnt = 0;
 	}
 	if (!priv->cnt)
-		priv->fmt_ctrl = NO_FMT;
+		priv->iface = NULL;
 	mutex_unlock(&priv->lock);
 }
 
@@ -265,13 +268,35 @@
 	return 0;
 }
 
+static bool ak4613_dai_fmt_matching(const struct ak4613_interface *iface,
+				    int is_play,
+				    unsigned int fmt, unsigned int width)
+{
+	const struct ak4613_formats *fmts;
+
+	fmts = (is_play) ? &iface->playback : &iface->capture;
+
+	if (fmts->fmt != fmt)
+		return false;
+
+	if (fmt == SND_SOC_DAIFMT_RIGHT_J) {
+		if (fmts->width != width)
+			return false;
+	} else {
+		if (fmts->width < width)
+			return false;
+	}
+
+	return true;
+}
+
 static int ak4613_dai_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 ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
-	const struct ak4613_formats *fmts;
+	const struct ak4613_interface *iface;
 	struct device *dev = codec->dev;
 	unsigned int width = params_width(params);
 	unsigned int fmt = priv->fmt;
@@ -305,33 +330,27 @@
 	 * It doesn't support TDM at this point
 	 */
 	fmt_ctrl = NO_FMT;
-	for (i = 0; i < ARRAY_SIZE(ak4613_iface); i++) {
-		fmts = (is_play) ?	&ak4613_iface[i].playback :
-					&ak4613_iface[i].capture;
-
-		if (fmts->fmt != fmt)
-			continue;
-
-		if (fmt == SND_SOC_DAIFMT_RIGHT_J) {
-			if (fmts->width != width)
-				continue;
-		} else {
-			if (fmts->width < width)
-				continue;
-		}
-
-		fmt_ctrl = AUDIO_IFACE_IDX_TO_VAL(i);
-		break;
-	}
-
 	ret = -EINVAL;
-	if (fmt_ctrl == NO_FMT)
-		goto hw_params_end;
+	iface = NULL;
 
 	mutex_lock(&priv->lock);
-	if ((priv->fmt_ctrl == NO_FMT) ||
-	    (priv->fmt_ctrl == fmt_ctrl)) {
-		priv->fmt_ctrl = fmt_ctrl;
+	if (priv->iface) {
+		if (ak4613_dai_fmt_matching(priv->iface, is_play, fmt, width))
+			iface = priv->iface;
+	} else {
+		for (i = ARRAY_SIZE(ak4613_iface); i >= 0; i--) {
+			if (!ak4613_dai_fmt_matching(ak4613_iface + i,
+						     is_play,
+						     fmt, width))
+				continue;
+			iface = ak4613_iface + i;
+			break;
+		}
+	}
+
+	if ((priv->iface == NULL) ||
+	    (priv->iface == iface)) {
+		priv->iface = iface;
 		priv->cnt++;
 		ret = 0;
 	}
@@ -340,8 +359,13 @@
 	if (ret < 0)
 		goto hw_params_end;
 
+	fmt_ctrl = AUDIO_IFACE_TO_VAL(iface);
+
 	snd_soc_update_bits(codec, CTRL1, FMT_MASK, fmt_ctrl);
-	snd_soc_write(codec, CTRL2, ctrl2);
+	snd_soc_update_bits(codec, CTRL2, DFS_MASK, ctrl2);
+
+	snd_soc_write(codec, ICTRL, priv->ic);
+	snd_soc_write(codec, OCTRL, priv->oc);
 
 hw_params_end:
 	if (ret < 0)
@@ -431,6 +455,28 @@
 	.num_dapm_routes	= ARRAY_SIZE(ak4613_intercon),
 };
 
+static void ak4613_parse_of(struct ak4613_priv *priv,
+			    struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	char prop[32];
+	int i;
+
+	/* Input 1 - 2 */
+	for (i = 0; i < 2; i++) {
+		snprintf(prop, sizeof(prop), "asahi-kasei,in%d-single-end", i + 1);
+		if (!of_get_property(np, prop, NULL))
+			priv->ic |= 1 << i;
+	}
+
+	/* Output 1 - 6 */
+	for (i = 0; i < 6; i++) {
+		snprintf(prop, sizeof(prop), "asahi-kasei,out%d-single-end", i + 1);
+		if (!of_get_property(np, prop, NULL))
+			priv->oc |= 1 << i;
+	}
+}
+
 static int ak4613_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -458,7 +504,9 @@
 	if (!priv)
 		return -ENOMEM;
 
-	priv->fmt_ctrl		= NO_FMT;
+	ak4613_parse_of(priv, dev);
+
+	priv->iface		= NULL;
 	priv->cnt		= 0;
 
 	mutex_init(&priv->lock);
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 93b4008..33143fe 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -310,7 +310,7 @@
 }
 EXPORT_SYMBOL_GPL(arizona_init_gpio);
 
-const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
+const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
 	"None",
 	"Tone Generator 1",
 	"Tone Generator 2",
@@ -418,7 +418,7 @@
 };
 EXPORT_SYMBOL_GPL(arizona_mixer_texts);
 
-int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
+unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
 	0x00,  /* None */
 	0x04,  /* Tone */
 	0x05,
@@ -555,12 +555,12 @@
 }
 EXPORT_SYMBOL_GPL(arizona_sample_rate_val_to_name);
 
-const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
+const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
 	"SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
 };
 EXPORT_SYMBOL_GPL(arizona_rate_text);
 
-const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
+const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
 	0, 1, 2, 8,
 };
 EXPORT_SYMBOL_GPL(arizona_rate_val);
@@ -702,6 +702,100 @@
 };
 EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
 
+static const char * const arizona_anc_input_src_text[] = {
+	"None", "IN1", "IN2", "IN3", "IN4",
+};
+
+static const char * const arizona_anc_channel_src_text[] = {
+	"None", "Left", "Right", "Combine",
+};
+
+const struct soc_enum arizona_anc_input_src[] = {
+	SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
+			ARIZONA_IN_RXANCL_SEL_SHIFT,
+			ARRAY_SIZE(arizona_anc_input_src_text),
+			arizona_anc_input_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL,
+			ARIZONA_FCL_MIC_MODE_SEL,
+			ARRAY_SIZE(arizona_anc_channel_src_text),
+			arizona_anc_channel_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
+			ARIZONA_IN_RXANCR_SEL_SHIFT,
+			ARRAY_SIZE(arizona_anc_input_src_text),
+			arizona_anc_input_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL,
+			ARIZONA_FCR_MIC_MODE_SEL,
+			ARRAY_SIZE(arizona_anc_channel_src_text),
+			arizona_anc_channel_src_text),
+};
+EXPORT_SYMBOL_GPL(arizona_anc_input_src);
+
+static const char * const arizona_anc_ng_texts[] = {
+	"None",
+	"Internal",
+	"External",
+};
+
+SOC_ENUM_SINGLE_DECL(arizona_anc_ng_enum, SND_SOC_NOPM, 0,
+		     arizona_anc_ng_texts);
+EXPORT_SYMBOL_GPL(arizona_anc_ng_enum);
+
+static const char * const arizona_output_anc_src_text[] = {
+	"None", "RXANCL", "RXANCR",
+};
+
+const struct soc_enum arizona_output_anc_src[] = {
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
+			ARIZONA_OUT1L_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1R,
+			ARIZONA_OUT1R_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
+			ARIZONA_OUT2L_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2R,
+			ARIZONA_OUT2R_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
+			ARIZONA_OUT3L_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_DAC_VOLUME_LIMIT_3R,
+			ARIZONA_OUT3R_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4L,
+			ARIZONA_OUT4L_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4R,
+			ARIZONA_OUT4R_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5L,
+			ARIZONA_OUT5L_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5R,
+			ARIZONA_OUT5R_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6L,
+			ARIZONA_OUT6L_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6R,
+			ARIZONA_OUT6R_ANC_SRC_SHIFT,
+			ARRAY_SIZE(arizona_output_anc_src_text),
+			arizona_output_anc_src_text),
+};
+EXPORT_SYMBOL_GPL(arizona_output_anc_src);
+
 static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
 {
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
@@ -1023,6 +1117,31 @@
 }
 EXPORT_SYMBOL_GPL(arizona_init_dvfs);
 
+int arizona_anc_ev(struct snd_soc_dapm_widget *w,
+		   struct snd_kcontrol *kcontrol,
+		   int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	unsigned int mask = 0x3 << w->shift;
+	unsigned int val;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		val = 1 << w->shift;
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		val = 1 << (w->shift + 1);
+		break;
+	default:
+		return 0;
+	}
+
+	snd_soc_update_bits(codec, ARIZONA_CLOCK_CONTROL, mask, val);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_anc_ev);
+
 static unsigned int arizona_opclk_ref_48k_rates[] = {
 	6144000,
 	12288000,
@@ -1095,7 +1214,7 @@
 	unsigned int reg;
 	unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
 	unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
-	unsigned int *clk;
+	int *clk;
 
 	switch (clk_id) {
 	case ARIZONA_CLK_SYSCLK:
@@ -1375,6 +1494,9 @@
 	const struct snd_pcm_hw_constraint_list *constraint;
 	unsigned int base_rate;
 
+	if (!substream->runtime)
+		return 0;
+
 	switch (dai_priv->clk) {
 	case ARIZONA_CLK_SYSCLK:
 		base_rate = priv->sysclk;
@@ -1901,18 +2023,18 @@
 	}
 
 	switch (fll->arizona->type) {
+	case WM5102:
+	case WM8997:
+		return init_ratio;
 	case WM5110:
 	case WM8280:
 		if (fll->arizona->rev < 3 || sync)
 			return init_ratio;
 		break;
-	case WM8998:
-	case WM1814:
+	default:
 		if (sync)
 			return init_ratio;
 		break;
-	default:
-		return init_ratio;
 	}
 
 	cfg->fratio = init_ratio - 1;
@@ -2093,9 +2215,9 @@
 		/* Facilitate smooth refclk across the transition */
 		regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
 					 ARIZONA_FLL1_GAIN_MASK, 0);
-		regmap_update_bits_async(fll->arizona->regmap, fll->base + 1,
-					 ARIZONA_FLL1_FREERUN,
-					 ARIZONA_FLL1_FREERUN);
+		regmap_update_bits(fll->arizona->regmap, fll->base + 1,
+				   ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
+		udelay(32);
 	}
 
 	/*
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index fea8b8a..8b6adb5 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -57,7 +57,7 @@
 #define ARIZONA_CLK_98MHZ  5
 #define ARIZONA_CLK_147MHZ 6
 
-#define ARIZONA_MAX_DAI  6
+#define ARIZONA_MAX_DAI  8
 #define ARIZONA_MAX_ADSP 4
 
 #define ARIZONA_DVFS_SR1_RQ	0x001
@@ -96,8 +96,8 @@
 #define ARIZONA_NUM_MIXER_INPUTS 104
 
 extern const unsigned int arizona_mixer_tlv[];
-extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
-extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
+extern const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
+extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
 
 #define ARIZONA_GAINMUX_CONTROLS(name, base) \
 	SOC_SINGLE_RANGE_TLV(name " Input Volume", base + 1,		\
@@ -216,8 +216,8 @@
 #define ARIZONA_RATE_ENUM_SIZE 4
 #define ARIZONA_SAMPLE_RATE_ENUM_SIZE 14
 
-extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
-extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
+extern const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
+extern const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
 extern const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE];
 extern const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE];
 
@@ -242,6 +242,10 @@
 
 extern const struct snd_kcontrol_new arizona_adsp2_rate_controls[];
 
+extern const struct soc_enum arizona_anc_input_src[];
+extern const struct soc_enum arizona_anc_ng_enum;
+extern const struct soc_enum arizona_output_anc_src[];
+
 extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol,
 			 int event);
@@ -251,6 +255,9 @@
 extern int arizona_hp_ev(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol,
 			 int event);
+extern int arizona_anc_ev(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol,
+			  int event);
 
 extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol);
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
new file mode 100644
index 0000000..dc5ae7f
--- /dev/null
+++ b/sound/soc/codecs/cs47l24.c
@@ -0,0 +1,1148 @@
+/*
+ * cs47l24.h  --  ALSA SoC Audio driver for Cirrus Logic CS47L24
+ *
+ * Copyright 2015 Cirrus Logic Inc.
+ *
+ * Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.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/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+#include "wm_adsp.h"
+#include "cs47l24.h"
+
+struct cs47l24_priv {
+	struct arizona_priv core;
+	struct arizona_fll fll[2];
+};
+
+static const struct wm_adsp_region cs47l24_dsp2_regions[] = {
+	{ .type = WMFW_ADSP2_PM, .base = 0x200000 },
+	{ .type = WMFW_ADSP2_ZM, .base = 0x280000 },
+	{ .type = WMFW_ADSP2_XM, .base = 0x290000 },
+	{ .type = WMFW_ADSP2_YM, .base = 0x2a8000 },
+};
+
+static const struct wm_adsp_region cs47l24_dsp3_regions[] = {
+	{ .type = WMFW_ADSP2_PM, .base = 0x300000 },
+	{ .type = WMFW_ADSP2_ZM, .base = 0x380000 },
+	{ .type = WMFW_ADSP2_XM, .base = 0x390000 },
+	{ .type = WMFW_ADSP2_YM, .base = 0x3a8000 },
+};
+
+static const struct wm_adsp_region *cs47l24_dsp_regions[] = {
+	cs47l24_dsp2_regions,
+	cs47l24_dsp3_regions,
+};
+
+static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0);
+static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
+
+#define CS47L24_NG_SRC(name, base) \
+	SOC_SINGLE(name " NG HPOUT1L Switch",  base,  0, 1, 0), \
+	SOC_SINGLE(name " NG HPOUT1R Switch",  base,  1, 1, 0), \
+	SOC_SINGLE(name " NG SPKOUT Switch",  base,  6, 1, 0)
+
+static const struct snd_kcontrol_new cs47l24_snd_controls[] = {
+SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]),
+SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
+
+SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum),
+
+SOC_SINGLE("IN1L HPF Switch", ARIZONA_IN1L_CONTROL,
+	   ARIZONA_IN1L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN1R HPF Switch", ARIZONA_IN1R_CONTROL,
+	   ARIZONA_IN1R_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2L HPF Switch", ARIZONA_IN2L_CONTROL,
+	   ARIZONA_IN2L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2R HPF Switch", ARIZONA_IN2R_CONTROL,
+	   ARIZONA_IN2R_HPF_SHIFT, 1, 0),
+
+SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
+	       ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
+	       ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
+	       ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R,
+	       ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+
+SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
+SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
+
+ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
+
+ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2),
+SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2),
+SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC2L", ARIZONA_DRC2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC2R", ARIZONA_DRC2RMIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5,
+		   ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA),
+SND_SOC_BYTES_MASK("DRC2", ARIZONA_DRC2_CTRL1, 5,
+		   ARIZONA_DRC2R_ENA | ARIZONA_DRC2L_ENA),
+
+ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
+
+ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2),
+ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2),
+ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2),
+ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2),
+
+SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
+SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
+SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
+SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
+
+SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+SOC_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]),
+SOC_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]),
+SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
+SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
+SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
+
+ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP3R", ARIZONA_DSP3RMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR,
+	       ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv),
+
+ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUT", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE("HPOUT1 SC Protect Switch", ARIZONA_HP1_SHORT_CIRCUIT_CTRL,
+	   ARIZONA_HP1_SC_ENA_SHIFT, 1, 0),
+
+SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_SINGLE("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	     ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+		 ARIZONA_OUT4L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+
+SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
+SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
+
+SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL,
+	   ARIZONA_NGATE_ENA_SHIFT, 1, 0),
+SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL,
+	       ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
+SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
+
+CS47L24_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L),
+CS47L24_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R),
+CS47L24_NG_SRC("SPKOUT", ARIZONA_NOISE_GATE_SELECT_4L),
+
+ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX3", ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX4", ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX5", ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
+};
+
+ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC2L, ARIZONA_DRC2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC2R, ARIZONA_DRC2RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP2L, ARIZONA_DSP2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP2R, ARIZONA_DSP2RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP2, ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP3L, ARIZONA_DSP3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP3R, ARIZONA_DSP3RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP3, ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUT, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX3, ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX4, ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX5, ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX6, ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT3, ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT4, ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC3, ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC4, ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT3, ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT4, ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC3, ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC4, ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC3INT1, ARIZONA_ISRC3INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT2, ARIZONA_ISRC3INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT3, ARIZONA_ISRC3INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT4, ARIZONA_ISRC3INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC3DEC1, ARIZONA_ISRC3DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC2, ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC3, ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC4, ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE);
+
+static const char * const cs47l24_aec_loopback_texts[] = {
+	"HPOUT1L", "HPOUT1R", "SPKOUT",
+};
+
+static const unsigned int cs47l24_aec_loopback_values[] = {
+	0, 1, 6,
+};
+
+static const struct soc_enum cs47l24_aec_loopback =
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
+			      ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+			      ARRAY_SIZE(cs47l24_aec_loopback_texts),
+			      cs47l24_aec_loopback_texts,
+			      cs47l24_aec_loopback_values);
+
+static const struct snd_kcontrol_new cs47l24_aec_loopback_mux =
+	SOC_DAPM_ENUM("AEC Loopback", cs47l24_aec_loopback);
+
+static const struct snd_soc_dapm_widget cs47l24_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1,
+		    ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
+		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+		    ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDD", 0, 0),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_SIGGEN("NOISE"),
+SND_SOC_DAPM_SIGGEN("HAPTICS"),
+
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+
+SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
+SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"),
+
+SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR,
+		 ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC2L", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC2R", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2R_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT,
+		 0, NULL, 0),
+SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT,
+		 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ASRC1L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("ASRC1R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1R_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
+		 NULL, 0),
+
+WM_ADSP2("DSP2", 1),
+WM_ADSP2("DSP3", 2),
+
+SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT3", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT4", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC3", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC4", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT3", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT4", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC3", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC4", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3INT1", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT2", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT3", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT4", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3DEC1", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC2", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3,
+		 ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+		       ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
+		       &cs47l24_aec_loopback_mux),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0,
+		     ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0,
+		     ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
+		    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
+		    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
+		   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
+		   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"),
+ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"),
+
+ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"),
+ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"),
+ARIZONA_MIXER_WIDGETS(DRC2L, "DRC2L"),
+ARIZONA_MIXER_WIDGETS(DRC2R, "DRC2R"),
+
+ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"),
+ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"),
+ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"),
+ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"),
+
+ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"),
+ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"),
+
+ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"),
+ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"),
+ARIZONA_MIXER_WIDGETS(SPKOUT, "SPKOUT"),
+
+ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
+ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
+
+ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
+ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+ARIZONA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"),
+ARIZONA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"),
+ARIZONA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"),
+ARIZONA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"),
+
+ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
+ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
+
+ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"),
+ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
+ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
+ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"),
+
+ARIZONA_DSP_WIDGETS(DSP2, "DSP2"),
+ARIZONA_DSP_WIDGETS(DSP3, "DSP3"),
+
+ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
+ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
+ARIZONA_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"),
+ARIZONA_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC3, "ISRC2DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC4, "ISRC2DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
+ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
+ARIZONA_MUX_WIDGETS(ISRC2INT3, "ISRC2INT3"),
+ARIZONA_MUX_WIDGETS(ISRC2INT4, "ISRC2INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC3DEC1, "ISRC3DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC2, "ISRC3DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC3, "ISRC3DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC4, "ISRC3DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC3INT1, "ISRC3INT1"),
+ARIZONA_MUX_WIDGETS(ISRC3INT2, "ISRC3INT2"),
+ARIZONA_MUX_WIDGETS(ISRC3INT3, "ISRC3INT3"),
+ARIZONA_MUX_WIDGETS(ISRC3INT4, "ISRC3INT4"),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+
+SND_SOC_DAPM_OUTPUT("MICSUPP"),
+};
+
+#define ARIZONA_MIXER_INPUT_ROUTES(name)	\
+	{ name, "Noise Generator", "Noise Generator" }, \
+	{ name, "Tone Generator 1", "Tone Generator 1" }, \
+	{ name, "Tone Generator 2", "Tone Generator 2" }, \
+	{ name, "Haptics", "HAPTICS" }, \
+	{ name, "AEC", "AEC Loopback" }, \
+	{ name, "IN1L", "IN1L PGA" }, \
+	{ name, "IN1R", "IN1R PGA" }, \
+	{ name, "IN2L", "IN2L PGA" }, \
+	{ name, "IN2R", "IN2R PGA" }, \
+	{ name, "AIF1RX1", "AIF1RX1" }, \
+	{ name, "AIF1RX2", "AIF1RX2" }, \
+	{ name, "AIF1RX3", "AIF1RX3" }, \
+	{ name, "AIF1RX4", "AIF1RX4" }, \
+	{ name, "AIF1RX5", "AIF1RX5" }, \
+	{ name, "AIF1RX6", "AIF1RX6" }, \
+	{ name, "AIF1RX7", "AIF1RX7" }, \
+	{ name, "AIF1RX8", "AIF1RX8" }, \
+	{ name, "AIF2RX1", "AIF2RX1" }, \
+	{ name, "AIF2RX2", "AIF2RX2" }, \
+	{ name, "AIF2RX3", "AIF2RX3" }, \
+	{ name, "AIF2RX4", "AIF2RX4" }, \
+	{ name, "AIF2RX5", "AIF2RX5" }, \
+	{ name, "AIF2RX6", "AIF2RX6" }, \
+	{ name, "AIF3RX1", "AIF3RX1" }, \
+	{ name, "AIF3RX2", "AIF3RX2" }, \
+	{ name, "EQ1", "EQ1" }, \
+	{ name, "EQ2", "EQ2" }, \
+	{ name, "DRC1L", "DRC1L" }, \
+	{ name, "DRC1R", "DRC1R" }, \
+	{ name, "DRC2L", "DRC2L" }, \
+	{ name, "DRC2R", "DRC2R" }, \
+	{ name, "LHPF1", "LHPF1" }, \
+	{ name, "LHPF2", "LHPF2" }, \
+	{ name, "LHPF3", "LHPF3" }, \
+	{ name, "LHPF4", "LHPF4" }, \
+	{ name, "ASRC1L", "ASRC1L" }, \
+	{ name, "ASRC1R", "ASRC1R" }, \
+	{ name, "ASRC2L", "ASRC2L" }, \
+	{ name, "ASRC2R", "ASRC2R" }, \
+	{ name, "ISRC1DEC1", "ISRC1DEC1" }, \
+	{ name, "ISRC1DEC2", "ISRC1DEC2" }, \
+	{ name, "ISRC1DEC3", "ISRC1DEC3" }, \
+	{ name, "ISRC1DEC4", "ISRC1DEC4" }, \
+	{ name, "ISRC1INT1", "ISRC1INT1" }, \
+	{ name, "ISRC1INT2", "ISRC1INT2" }, \
+	{ name, "ISRC1INT3", "ISRC1INT3" }, \
+	{ name, "ISRC1INT4", "ISRC1INT4" }, \
+	{ name, "ISRC2DEC1", "ISRC2DEC1" }, \
+	{ name, "ISRC2DEC2", "ISRC2DEC2" }, \
+	{ name, "ISRC2DEC3", "ISRC2DEC3" }, \
+	{ name, "ISRC2DEC4", "ISRC2DEC4" }, \
+	{ name, "ISRC2INT1", "ISRC2INT1" }, \
+	{ name, "ISRC2INT2", "ISRC2INT2" }, \
+	{ name, "ISRC2INT3", "ISRC2INT3" }, \
+	{ name, "ISRC2INT4", "ISRC2INT4" }, \
+	{ name, "ISRC3DEC1", "ISRC3DEC1" }, \
+	{ name, "ISRC3DEC2", "ISRC3DEC2" }, \
+	{ name, "ISRC3DEC3", "ISRC3DEC3" }, \
+	{ name, "ISRC3DEC4", "ISRC3DEC4" }, \
+	{ name, "ISRC3INT1", "ISRC3INT1" }, \
+	{ name, "ISRC3INT2", "ISRC3INT2" }, \
+	{ name, "ISRC3INT3", "ISRC3INT3" }, \
+	{ name, "ISRC3INT4", "ISRC3INT4" }, \
+	{ name, "DSP2.1", "DSP2" }, \
+	{ name, "DSP2.2", "DSP2" }, \
+	{ name, "DSP2.3", "DSP2" }, \
+	{ name, "DSP2.4", "DSP2" }, \
+	{ name, "DSP2.5", "DSP2" }, \
+	{ name, "DSP2.6", "DSP2" }, \
+	{ name, "DSP3.1", "DSP3" }, \
+	{ name, "DSP3.2", "DSP3" }, \
+	{ name, "DSP3.3", "DSP3" }, \
+	{ name, "DSP3.4", "DSP3" }, \
+	{ name, "DSP3.5", "DSP3" }, \
+	{ name, "DSP3.6", "DSP3" }
+
+static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = {
+	{ "OUT1L", NULL, "CPVDD" },
+	{ "OUT1R", NULL, "CPVDD" },
+
+	{ "OUT4L", NULL, "SPKVDD" },
+
+	{ "OUT1L", NULL, "SYSCLK" },
+	{ "OUT1R", NULL, "SYSCLK" },
+	{ "OUT4L", NULL, "SYSCLK" },
+
+	{ "IN1L", NULL, "SYSCLK" },
+	{ "IN1R", NULL, "SYSCLK" },
+	{ "IN2L", NULL, "SYSCLK" },
+	{ "IN2R", NULL, "SYSCLK" },
+
+	{ "MICBIAS1", NULL, "MICVDD" },
+	{ "MICBIAS2", NULL, "MICVDD" },
+
+	{ "Noise Generator", NULL, "SYSCLK" },
+	{ "Tone Generator 1", NULL, "SYSCLK" },
+	{ "Tone Generator 2", NULL, "SYSCLK" },
+
+	{ "Noise Generator", NULL, "NOISE" },
+	{ "Tone Generator 1", NULL, "TONE" },
+	{ "Tone Generator 2", NULL, "TONE" },
+
+	{ "AIF1 Capture", NULL, "AIF1TX1" },
+	{ "AIF1 Capture", NULL, "AIF1TX2" },
+	{ "AIF1 Capture", NULL, "AIF1TX3" },
+	{ "AIF1 Capture", NULL, "AIF1TX4" },
+	{ "AIF1 Capture", NULL, "AIF1TX5" },
+	{ "AIF1 Capture", NULL, "AIF1TX6" },
+	{ "AIF1 Capture", NULL, "AIF1TX7" },
+	{ "AIF1 Capture", NULL, "AIF1TX8" },
+
+	{ "AIF1RX1", NULL, "AIF1 Playback" },
+	{ "AIF1RX2", NULL, "AIF1 Playback" },
+	{ "AIF1RX3", NULL, "AIF1 Playback" },
+	{ "AIF1RX4", NULL, "AIF1 Playback" },
+	{ "AIF1RX5", NULL, "AIF1 Playback" },
+	{ "AIF1RX6", NULL, "AIF1 Playback" },
+	{ "AIF1RX7", NULL, "AIF1 Playback" },
+	{ "AIF1RX8", NULL, "AIF1 Playback" },
+
+	{ "AIF2 Capture", NULL, "AIF2TX1" },
+	{ "AIF2 Capture", NULL, "AIF2TX2" },
+	{ "AIF2 Capture", NULL, "AIF2TX3" },
+	{ "AIF2 Capture", NULL, "AIF2TX4" },
+	{ "AIF2 Capture", NULL, "AIF2TX5" },
+	{ "AIF2 Capture", NULL, "AIF2TX6" },
+
+	{ "AIF2RX1", NULL, "AIF2 Playback" },
+	{ "AIF2RX2", NULL, "AIF2 Playback" },
+	{ "AIF2RX3", NULL, "AIF2 Playback" },
+	{ "AIF2RX4", NULL, "AIF2 Playback" },
+	{ "AIF2RX5", NULL, "AIF2 Playback" },
+	{ "AIF2RX6", NULL, "AIF2 Playback" },
+
+	{ "AIF3 Capture", NULL, "AIF3TX1" },
+	{ "AIF3 Capture", NULL, "AIF3TX2" },
+
+	{ "AIF3RX1", NULL, "AIF3 Playback" },
+	{ "AIF3RX2", NULL, "AIF3 Playback" },
+
+	{ "AIF1 Playback", NULL, "SYSCLK" },
+	{ "AIF2 Playback", NULL, "SYSCLK" },
+	{ "AIF3 Playback", NULL, "SYSCLK" },
+
+	{ "AIF1 Capture", NULL, "SYSCLK" },
+	{ "AIF2 Capture", NULL, "SYSCLK" },
+	{ "AIF3 Capture", NULL, "SYSCLK" },
+
+	{ "IN1L PGA", NULL, "IN1L" },
+	{ "IN1R PGA", NULL, "IN1R" },
+
+	{ "IN2L PGA", NULL, "IN2L" },
+	{ "IN2R PGA", NULL, "IN2R" },
+
+	ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
+	ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
+
+	ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUT"),
+
+	ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"),
+	ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"),
+
+	ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+	ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+	ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+	ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+	ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+	ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+	ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
+	ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
+
+	ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
+	ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+	ARIZONA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"),
+	ARIZONA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"),
+	ARIZONA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"),
+	ARIZONA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"),
+
+	ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
+	ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
+
+	ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
+	ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
+
+	ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"),
+	ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"),
+	ARIZONA_MIXER_ROUTES("DRC2L", "DRC2L"),
+	ARIZONA_MIXER_ROUTES("DRC2R", "DRC2R"),
+
+	ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"),
+	ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"),
+	ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
+	ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
+
+	ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"),
+	ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"),
+	ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),
+	ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"),
+
+	ARIZONA_DSP_ROUTES("DSP2"),
+	ARIZONA_DSP_ROUTES("DSP3"),
+
+	ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+	ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
+	ARIZONA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"),
+	ARIZONA_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"),
+
+	ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"),
+
+	ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+	ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+	ARIZONA_MUX_ROUTES("ISRC2INT3", "ISRC2INT3"),
+	ARIZONA_MUX_ROUTES("ISRC2INT4", "ISRC2INT4"),
+
+	ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC3", "ISRC2DEC3"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC4", "ISRC2DEC4"),
+
+	ARIZONA_MUX_ROUTES("ISRC3INT1", "ISRC3INT1"),
+	ARIZONA_MUX_ROUTES("ISRC3INT2", "ISRC3INT2"),
+	ARIZONA_MUX_ROUTES("ISRC3INT3", "ISRC3INT3"),
+	ARIZONA_MUX_ROUTES("ISRC3INT4", "ISRC3INT4"),
+
+	ARIZONA_MUX_ROUTES("ISRC3DEC1", "ISRC3DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC3DEC2", "ISRC3DEC2"),
+	ARIZONA_MUX_ROUTES("ISRC3DEC3", "ISRC3DEC3"),
+	ARIZONA_MUX_ROUTES("ISRC3DEC4", "ISRC3DEC4"),
+
+	{ "AEC Loopback", "HPOUT1L", "OUT1L" },
+	{ "AEC Loopback", "HPOUT1R", "OUT1R" },
+	{ "HPOUT1L", NULL, "OUT1L" },
+	{ "HPOUT1R", NULL, "OUT1R" },
+
+	{ "AEC Loopback", "SPKOUT", "OUT4L" },
+	{ "SPKOUTN", NULL, "OUT4L" },
+	{ "SPKOUTP", NULL, "OUT4L" },
+
+	{ "MICSUPP", NULL, "SYSCLK" },
+
+	{ "DRC1 Signal Activity", NULL, "DRC1L" },
+	{ "DRC1 Signal Activity", NULL, "DRC1R" },
+	{ "DRC2 Signal Activity", NULL, "DRC2L" },
+	{ "DRC2 Signal Activity", NULL, "DRC2R" },
+};
+
+static int cs47l24_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+			  unsigned int Fref, unsigned int Fout)
+{
+	struct cs47l24_priv *cs47l24 = snd_soc_codec_get_drvdata(codec);
+
+	switch (fll_id) {
+	case CS47L24_FLL1:
+		return arizona_set_fll(&cs47l24->fll[0], source, Fref, Fout);
+	case CS47L24_FLL2:
+		return arizona_set_fll(&cs47l24->fll[1], source, Fref, Fout);
+	case CS47L24_FLL1_REFCLK:
+		return arizona_set_fll_refclk(&cs47l24->fll[0], source, Fref,
+					      Fout);
+	case CS47L24_FLL2_REFCLK:
+		return arizona_set_fll_refclk(&cs47l24->fll[1], source, Fref,
+					      Fout);
+	default:
+		return -EINVAL;
+	}
+}
+
+#define CS47L24_RATES SNDRV_PCM_RATE_8000_192000
+
+#define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver cs47l24_dai[] = {
+	{
+		.name = "cs47l24-aif1",
+		.id = 1,
+		.base = ARIZONA_AIF1_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = CS47L24_RATES,
+			.formats = CS47L24_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 8,
+			 .rates = CS47L24_RATES,
+			 .formats = CS47L24_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "cs47l24-aif2",
+		.id = 2,
+		.base = ARIZONA_AIF2_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = CS47L24_RATES,
+			.formats = CS47L24_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 6,
+			 .rates = CS47L24_RATES,
+			 .formats = CS47L24_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+	{
+		.name = "cs47l24-aif3",
+		.id = 3,
+		.base = ARIZONA_AIF3_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = CS47L24_RATES,
+			.formats = CS47L24_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF3 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = CS47L24_RATES,
+			 .formats = CS47L24_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+};
+
+static int cs47l24_codec_probe(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	priv->core.arizona->dapm = dapm;
+
+	arizona_init_spk(codec);
+	arizona_init_gpio(codec);
+	arizona_init_mono(codec);
+
+	ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec);
+	if (ret)
+		goto err_adsp2_codec_probe;
+
+	ret = wm_adsp2_codec_probe(&priv->core.adsp[2], codec);
+	if (ret)
+		goto err_adsp2_codec_probe;
+
+	ret = snd_soc_add_codec_controls(codec,
+					 &arizona_adsp2_rate_controls[1], 2);
+	if (ret)
+		goto err_adsp2_codec_probe;
+
+	snd_soc_dapm_disable_pin(dapm, "HAPTICS");
+
+	return 0;
+
+err_adsp2_codec_probe:
+	wm_adsp2_codec_remove(&priv->core.adsp[1], codec);
+	wm_adsp2_codec_remove(&priv->core.adsp[2], codec);
+
+	return ret;
+}
+
+static int cs47l24_codec_remove(struct snd_soc_codec *codec)
+{
+	struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+
+	wm_adsp2_codec_remove(&priv->core.adsp[1], codec);
+	wm_adsp2_codec_remove(&priv->core.adsp[2], codec);
+
+	priv->core.arizona->dapm = NULL;
+
+	return 0;
+}
+
+#define CS47L24_DIG_VU 0x0200
+
+static unsigned int cs47l24_digital_vu[] = {
+	ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	ARIZONA_DAC_DIGITAL_VOLUME_1R,
+	ARIZONA_DAC_DIGITAL_VOLUME_4L,
+};
+
+static struct regmap *cs47l24_get_regmap(struct device *dev)
+{
+	struct cs47l24_priv *priv = dev_get_drvdata(dev);
+
+	return priv->core.arizona->regmap;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = {
+	.probe = cs47l24_codec_probe,
+	.remove = cs47l24_codec_remove,
+	.get_regmap = cs47l24_get_regmap,
+
+	.idle_bias_off = true,
+
+	.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),
+};
+
+static int cs47l24_probe(struct platform_device *pdev)
+{
+	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+	struct cs47l24_priv *cs47l24;
+	int i, ret;
+
+	BUILD_BUG_ON(ARRAY_SIZE(cs47l24_dai) > ARIZONA_MAX_DAI);
+
+	cs47l24 = devm_kzalloc(&pdev->dev, sizeof(struct cs47l24_priv),
+			      GFP_KERNEL);
+	if (!cs47l24)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, cs47l24);
+
+	cs47l24->core.arizona = arizona;
+	cs47l24->core.num_inputs = 4;
+
+	for (i = 1; i <= 2; i++) {
+		cs47l24->core.adsp[i].part = "cs47l24";
+		cs47l24->core.adsp[i].num = i + 1;
+		cs47l24->core.adsp[i].type = WMFW_ADSP2;
+		cs47l24->core.adsp[i].dev = arizona->dev;
+		cs47l24->core.adsp[i].regmap = arizona->regmap;
+
+		cs47l24->core.adsp[i].base = ARIZONA_DSP1_CONTROL_1 +
+					     (0x100 * i);
+		cs47l24->core.adsp[i].mem = cs47l24_dsp_regions[i - 1];
+		cs47l24->core.adsp[i].num_mems =
+				ARRAY_SIZE(cs47l24_dsp2_regions);
+
+		ret = wm_adsp2_init(&cs47l24->core.adsp[i]);
+		if (ret != 0)
+			return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cs47l24->fll); i++)
+		cs47l24->fll[i].vco_mult = 3;
+
+	arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK,
+			 &cs47l24->fll[0]);
+	arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
+			 &cs47l24->fll[1]);
+
+	/* SR2 fixed at 8kHz, SR3 fixed at 16kHz */
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2,
+			   ARIZONA_SAMPLE_RATE_2_MASK, 0x11);
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3,
+			   ARIZONA_SAMPLE_RATE_3_MASK, 0x12);
+
+	for (i = 0; i < ARRAY_SIZE(cs47l24_dai); i++)
+		arizona_init_dai(&cs47l24->core, i);
+
+	/* Latch volume update bits */
+	for (i = 0; i < ARRAY_SIZE(cs47l24_digital_vu); i++)
+		regmap_update_bits(arizona->regmap, cs47l24_digital_vu[i],
+				   CS47L24_DIG_VU, CS47L24_DIG_VU);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_idle(&pdev->dev);
+
+	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24,
+				      cs47l24_dai, ARRAY_SIZE(cs47l24_dai));
+}
+
+static int cs47l24_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver cs47l24_codec_driver = {
+	.driver = {
+		.name = "cs47l24-codec",
+	},
+	.probe = cs47l24_probe,
+	.remove = cs47l24_remove,
+};
+
+module_platform_driver(cs47l24_codec_driver);
+
+MODULE_DESCRIPTION("ASoC CS47L24 driver");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:cs47l24-codec");
diff --git a/sound/soc/codecs/cs47l24.h b/sound/soc/codecs/cs47l24.h
new file mode 100644
index 0000000..77ab2b7
--- /dev/null
+++ b/sound/soc/codecs/cs47l24.h
@@ -0,0 +1,23 @@
+/*
+ * cs47l24.h  --  ALSA SoC Audio driver for Cirrus Logic CS47L24
+ *
+ * Copyright 2015 Cirrus Logic Inc.
+ *
+ * Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _CS47L24_H
+#define _CS47L24_H
+
+#include "arizona.h"
+
+#define CS47L24_FLL1        1
+#define CS47L24_FLL2        2
+#define CS47L24_FLL1_REFCLK 3
+#define CS47L24_FLL2_REFCLK 4
+
+#endif
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
new file mode 100644
index 0000000..93575f2
--- /dev/null
+++ b/sound/soc/codecs/da7218.c
@@ -0,0 +1,3341 @@
+/*
+ * da7218.c - DA7218 ALSA SoC Codec Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <asm/div64.h>
+
+#include <sound/da7218.h>
+#include "da7218.h"
+
+
+/*
+ * TLVs and Enums
+ */
+
+/* Input TLVs */
+static const DECLARE_TLV_DB_SCALE(da7218_mic_gain_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_mixin_gain_tlv, -450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_in_dig_gain_tlv, -8325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_ags_trigger_tlv, -9000, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_ags_att_max_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_alc_threshold_tlv, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_alc_gain_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_alc_ana_gain_tlv, 0, 600, 0);
+
+/* Input/Output TLVs */
+static const DECLARE_TLV_DB_SCALE(da7218_dmix_gain_tlv, -4200, 150, 0);
+
+/* Output TLVs */
+static const DECLARE_TLV_DB_SCALE(da7218_dgs_trigger_tlv, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_dgs_anticlip_tlv, -4200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_dgs_signal_tlv, -9000, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_out_eq_band_tlv, -1050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_out_dig_gain_tlv, -8325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_dac_ng_threshold_tlv, -10200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_mixout_gain_tlv, -100, 50, 0);
+static const DECLARE_TLV_DB_SCALE(da7218_hp_gain_tlv, -5700, 150, 0);
+
+/* Input Enums */
+static const char * const da7218_alc_attack_rate_txt[] = {
+	"7.33/fs", "14.66/fs", "29.32/fs", "58.64/fs", "117.3/fs", "234.6/fs",
+	"469.1/fs", "938.2/fs", "1876/fs", "3753/fs", "7506/fs", "15012/fs",
+	"30024/fs",
+};
+
+static const struct soc_enum da7218_alc_attack_rate =
+	SOC_ENUM_SINGLE(DA7218_ALC_CTRL2, DA7218_ALC_ATTACK_SHIFT,
+			DA7218_ALC_ATTACK_MAX, da7218_alc_attack_rate_txt);
+
+static const char * const da7218_alc_release_rate_txt[] = {
+	"28.66/fs", "57.33/fs", "114.6/fs", "229.3/fs", "458.6/fs", "917.1/fs",
+	"1834/fs", "3668/fs", "7337/fs", "14674/fs", "29348/fs",
+};
+
+static const struct soc_enum da7218_alc_release_rate =
+	SOC_ENUM_SINGLE(DA7218_ALC_CTRL2, DA7218_ALC_RELEASE_SHIFT,
+			DA7218_ALC_RELEASE_MAX, da7218_alc_release_rate_txt);
+
+static const char * const da7218_alc_hold_time_txt[] = {
+	"62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs",
+	"7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs",
+	"253952/fs", "507904/fs", "1015808/fs", "2031616/fs"
+};
+
+static const struct soc_enum da7218_alc_hold_time =
+	SOC_ENUM_SINGLE(DA7218_ALC_CTRL3, DA7218_ALC_HOLD_SHIFT,
+			DA7218_ALC_HOLD_MAX, da7218_alc_hold_time_txt);
+
+static const char * const da7218_alc_anticlip_step_txt[] = {
+	"0.034dB/fs", "0.068dB/fs", "0.136dB/fs", "0.272dB/fs",
+};
+
+static const struct soc_enum da7218_alc_anticlip_step =
+	SOC_ENUM_SINGLE(DA7218_ALC_ANTICLIP_CTRL,
+			DA7218_ALC_ANTICLIP_STEP_SHIFT,
+			DA7218_ALC_ANTICLIP_STEP_MAX,
+			da7218_alc_anticlip_step_txt);
+
+static const char * const da7218_integ_rate_txt[] = {
+	"1/4", "1/16", "1/256", "1/65536"
+};
+
+static const struct soc_enum da7218_integ_attack_rate =
+	SOC_ENUM_SINGLE(DA7218_ENV_TRACK_CTRL, DA7218_INTEG_ATTACK_SHIFT,
+			DA7218_INTEG_MAX, da7218_integ_rate_txt);
+
+static const struct soc_enum da7218_integ_release_rate =
+	SOC_ENUM_SINGLE(DA7218_ENV_TRACK_CTRL, DA7218_INTEG_RELEASE_SHIFT,
+			DA7218_INTEG_MAX, da7218_integ_rate_txt);
+
+/* Input/Output Enums */
+static const char * const da7218_gain_ramp_rate_txt[] = {
+	"Nominal Rate * 8", "Nominal Rate", "Nominal Rate / 8",
+	"Nominal Rate / 16",
+};
+
+static const struct soc_enum da7218_gain_ramp_rate =
+	SOC_ENUM_SINGLE(DA7218_GAIN_RAMP_CTRL, DA7218_GAIN_RAMP_RATE_SHIFT,
+			DA7218_GAIN_RAMP_RATE_MAX, da7218_gain_ramp_rate_txt);
+
+static const char * const da7218_hpf_mode_txt[] = {
+	"Disabled", "Audio", "Voice",
+};
+
+static const unsigned int da7218_hpf_mode_val[] = {
+	DA7218_HPF_DISABLED, DA7218_HPF_AUDIO_EN, DA7218_HPF_VOICE_EN,
+};
+
+static const struct soc_enum da7218_in1_hpf_mode =
+	SOC_VALUE_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL,
+			      DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK,
+			      DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt,
+			      da7218_hpf_mode_val);
+
+static const struct soc_enum da7218_in2_hpf_mode =
+	SOC_VALUE_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL,
+			      DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK,
+			      DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt,
+			      da7218_hpf_mode_val);
+
+static const struct soc_enum da7218_out1_hpf_mode =
+	SOC_VALUE_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL,
+			      DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK,
+			      DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt,
+			      da7218_hpf_mode_val);
+
+static const char * const da7218_audio_hpf_corner_txt[] = {
+	"2Hz", "4Hz", "8Hz", "16Hz",
+};
+
+static const struct soc_enum da7218_in1_audio_hpf_corner =
+	SOC_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL,
+			DA7218_IN_1_AUDIO_HPF_CORNER_SHIFT,
+			DA7218_AUDIO_HPF_CORNER_MAX,
+			da7218_audio_hpf_corner_txt);
+
+static const struct soc_enum da7218_in2_audio_hpf_corner =
+	SOC_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL,
+			DA7218_IN_2_AUDIO_HPF_CORNER_SHIFT,
+			DA7218_AUDIO_HPF_CORNER_MAX,
+			da7218_audio_hpf_corner_txt);
+
+static const struct soc_enum da7218_out1_audio_hpf_corner =
+	SOC_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL,
+			DA7218_OUT_1_AUDIO_HPF_CORNER_SHIFT,
+			DA7218_AUDIO_HPF_CORNER_MAX,
+			da7218_audio_hpf_corner_txt);
+
+static const char * const da7218_voice_hpf_corner_txt[] = {
+	"2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz",
+};
+
+static const struct soc_enum da7218_in1_voice_hpf_corner =
+	SOC_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL,
+			DA7218_IN_1_VOICE_HPF_CORNER_SHIFT,
+			DA7218_VOICE_HPF_CORNER_MAX,
+			da7218_voice_hpf_corner_txt);
+
+static const struct soc_enum da7218_in2_voice_hpf_corner =
+	SOC_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL,
+			DA7218_IN_2_VOICE_HPF_CORNER_SHIFT,
+			DA7218_VOICE_HPF_CORNER_MAX,
+			da7218_voice_hpf_corner_txt);
+
+static const struct soc_enum da7218_out1_voice_hpf_corner =
+	SOC_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL,
+			DA7218_OUT_1_VOICE_HPF_CORNER_SHIFT,
+			DA7218_VOICE_HPF_CORNER_MAX,
+			da7218_voice_hpf_corner_txt);
+
+static const char * const da7218_tonegen_dtmf_key_txt[] = {
+	"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D",
+	"*", "#"
+};
+
+static const struct soc_enum da7218_tonegen_dtmf_key =
+	SOC_ENUM_SINGLE(DA7218_TONE_GEN_CFG1, DA7218_DTMF_REG_SHIFT,
+			DA7218_DTMF_REG_MAX, da7218_tonegen_dtmf_key_txt);
+
+static const char * const da7218_tonegen_swg_sel_txt[] = {
+	"Sum", "SWG1", "SWG2", "SWG1_1-Cos"
+};
+
+static const struct soc_enum da7218_tonegen_swg_sel =
+	SOC_ENUM_SINGLE(DA7218_TONE_GEN_CFG2, DA7218_SWG_SEL_SHIFT,
+			DA7218_SWG_SEL_MAX, da7218_tonegen_swg_sel_txt);
+
+/* Output Enums */
+static const char * const da7218_dgs_rise_coeff_txt[] = {
+	"1/1", "1/16", "1/64", "1/256", "1/1024", "1/4096", "1/16384",
+};
+
+static const struct soc_enum da7218_dgs_rise_coeff =
+	SOC_ENUM_SINGLE(DA7218_DGS_RISE_FALL, DA7218_DGS_RISE_COEFF_SHIFT,
+			DA7218_DGS_RISE_COEFF_MAX, da7218_dgs_rise_coeff_txt);
+
+static const char * const da7218_dgs_fall_coeff_txt[] = {
+	"1/4", "1/16", "1/64", "1/256", "1/1024", "1/4096", "1/16384", "1/65536",
+};
+
+static const struct soc_enum da7218_dgs_fall_coeff =
+	SOC_ENUM_SINGLE(DA7218_DGS_RISE_FALL, DA7218_DGS_FALL_COEFF_SHIFT,
+			DA7218_DGS_FALL_COEFF_MAX, da7218_dgs_fall_coeff_txt);
+
+static const char * const da7218_dac_ng_setup_time_txt[] = {
+	"256 Samples", "512 Samples", "1024 Samples", "2048 Samples"
+};
+
+static const struct soc_enum da7218_dac_ng_setup_time =
+	SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME,
+			DA7218_DAC_NG_SETUP_TIME_SHIFT,
+			DA7218_DAC_NG_SETUP_TIME_MAX,
+			da7218_dac_ng_setup_time_txt);
+
+static const char * const da7218_dac_ng_rampup_txt[] = {
+	"0.22ms/dB", "0.0138ms/dB"
+};
+
+static const struct soc_enum da7218_dac_ng_rampup_rate =
+	SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME,
+			DA7218_DAC_NG_RAMPUP_RATE_SHIFT,
+			DA7218_DAC_NG_RAMPUP_RATE_MAX,
+			da7218_dac_ng_rampup_txt);
+
+static const char * const da7218_dac_ng_rampdown_txt[] = {
+	"0.88ms/dB", "14.08ms/dB"
+};
+
+static const struct soc_enum da7218_dac_ng_rampdown_rate =
+	SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME,
+			DA7218_DAC_NG_RAMPDN_RATE_SHIFT,
+			DA7218_DAC_NG_RAMPDN_RATE_MAX,
+			da7218_dac_ng_rampdown_txt);
+
+static const char * const da7218_cp_mchange_txt[] = {
+	"Largest Volume", "DAC Volume", "Signal Magnitude"
+};
+
+static const unsigned int da7218_cp_mchange_val[] = {
+	DA7218_CP_MCHANGE_LARGEST_VOL, DA7218_CP_MCHANGE_DAC_VOL,
+	DA7218_CP_MCHANGE_SIG_MAG
+};
+
+static const struct soc_enum da7218_cp_mchange =
+	SOC_VALUE_ENUM_SINGLE(DA7218_CP_CTRL, DA7218_CP_MCHANGE_SHIFT,
+			      DA7218_CP_MCHANGE_REL_MASK, DA7218_CP_MCHANGE_MAX,
+			      da7218_cp_mchange_txt, da7218_cp_mchange_val);
+
+static const char * const da7218_cp_fcontrol_txt[] = {
+	"1MHz", "500KHz", "250KHz", "125KHz", "63KHz", "0KHz"
+};
+
+static const struct soc_enum da7218_cp_fcontrol =
+	SOC_ENUM_SINGLE(DA7218_CP_DELAY, DA7218_CP_FCONTROL_SHIFT,
+			DA7218_CP_FCONTROL_MAX, da7218_cp_fcontrol_txt);
+
+static const char * const da7218_cp_tau_delay_txt[] = {
+	"0ms", "2ms", "4ms", "16ms", "64ms", "128ms", "256ms", "512ms"
+};
+
+static const struct soc_enum da7218_cp_tau_delay =
+	SOC_ENUM_SINGLE(DA7218_CP_DELAY, DA7218_CP_TAU_DELAY_SHIFT,
+			DA7218_CP_TAU_DELAY_MAX, da7218_cp_tau_delay_txt);
+
+/*
+ * Control Functions
+ */
+
+/* ALC */
+static void da7218_alc_calib(struct snd_soc_codec *codec)
+{
+	u8 mic_1_ctrl, mic_2_ctrl;
+	u8 mixin_1_ctrl, mixin_2_ctrl;
+	u8 in_1l_filt_ctrl, in_1r_filt_ctrl, in_2l_filt_ctrl, in_2r_filt_ctrl;
+	u8 in_1_hpf_ctrl, in_2_hpf_ctrl;
+	u8 calib_ctrl;
+	int i = 0;
+	bool calibrated = false;
+
+	/* Save current state of MIC control registers */
+	mic_1_ctrl = snd_soc_read(codec, DA7218_MIC_1_CTRL);
+	mic_2_ctrl = snd_soc_read(codec, DA7218_MIC_2_CTRL);
+
+	/* Save current state of input mixer control registers */
+	mixin_1_ctrl = snd_soc_read(codec, DA7218_MIXIN_1_CTRL);
+	mixin_2_ctrl = snd_soc_read(codec, DA7218_MIXIN_2_CTRL);
+
+	/* Save current state of input filter control registers */
+	in_1l_filt_ctrl = snd_soc_read(codec, DA7218_IN_1L_FILTER_CTRL);
+	in_1r_filt_ctrl = snd_soc_read(codec, DA7218_IN_1R_FILTER_CTRL);
+	in_2l_filt_ctrl = snd_soc_read(codec, DA7218_IN_2L_FILTER_CTRL);
+	in_2r_filt_ctrl = snd_soc_read(codec, DA7218_IN_2R_FILTER_CTRL);
+
+	/* Save current state of input HPF control registers */
+	in_1_hpf_ctrl = snd_soc_read(codec, DA7218_IN_1_HPF_FILTER_CTRL);
+	in_2_hpf_ctrl = snd_soc_read(codec, DA7218_IN_2_HPF_FILTER_CTRL);
+
+	/* Enable then Mute MIC PGAs */
+	snd_soc_update_bits(codec, DA7218_MIC_1_CTRL, DA7218_MIC_1_AMP_EN_MASK,
+			    DA7218_MIC_1_AMP_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_MIC_2_CTRL, DA7218_MIC_2_AMP_EN_MASK,
+			    DA7218_MIC_2_AMP_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_MIC_1_CTRL,
+			    DA7218_MIC_1_AMP_MUTE_EN_MASK,
+			    DA7218_MIC_1_AMP_MUTE_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_MIC_2_CTRL,
+			    DA7218_MIC_2_AMP_MUTE_EN_MASK,
+			    DA7218_MIC_2_AMP_MUTE_EN_MASK);
+
+	/* Enable input mixers unmuted */
+	snd_soc_update_bits(codec, DA7218_MIXIN_1_CTRL,
+			    DA7218_MIXIN_1_AMP_EN_MASK |
+			    DA7218_MIXIN_1_AMP_MUTE_EN_MASK,
+			    DA7218_MIXIN_1_AMP_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_MIXIN_2_CTRL,
+			    DA7218_MIXIN_2_AMP_EN_MASK |
+			    DA7218_MIXIN_2_AMP_MUTE_EN_MASK,
+			    DA7218_MIXIN_2_AMP_EN_MASK);
+
+	/* Enable input filters unmuted */
+	snd_soc_update_bits(codec, DA7218_IN_1L_FILTER_CTRL,
+			    DA7218_IN_1L_FILTER_EN_MASK |
+			    DA7218_IN_1L_MUTE_EN_MASK,
+			    DA7218_IN_1L_FILTER_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_IN_1R_FILTER_CTRL,
+			    DA7218_IN_1R_FILTER_EN_MASK |
+			    DA7218_IN_1R_MUTE_EN_MASK,
+			    DA7218_IN_1R_FILTER_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_IN_2L_FILTER_CTRL,
+			    DA7218_IN_2L_FILTER_EN_MASK |
+			    DA7218_IN_2L_MUTE_EN_MASK,
+			    DA7218_IN_2L_FILTER_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_IN_2R_FILTER_CTRL,
+			    DA7218_IN_2R_FILTER_EN_MASK |
+			    DA7218_IN_2R_MUTE_EN_MASK,
+			    DA7218_IN_2R_FILTER_EN_MASK);
+
+	/*
+	 * Make sure input HPFs voice mode is disabled, otherwise for sampling
+	 * rates above 32KHz the ADC signals will be stopped and will cause
+	 * calibration to lock up.
+	 */
+	snd_soc_update_bits(codec, DA7218_IN_1_HPF_FILTER_CTRL,
+			    DA7218_IN_1_VOICE_EN_MASK, 0);
+	snd_soc_update_bits(codec, DA7218_IN_2_HPF_FILTER_CTRL,
+			    DA7218_IN_2_VOICE_EN_MASK, 0);
+
+	/* Perform auto calibration */
+	snd_soc_update_bits(codec, DA7218_CALIB_CTRL, DA7218_CALIB_AUTO_EN_MASK,
+			    DA7218_CALIB_AUTO_EN_MASK);
+	do {
+		calib_ctrl = snd_soc_read(codec, DA7218_CALIB_CTRL);
+		if (calib_ctrl & DA7218_CALIB_AUTO_EN_MASK) {
+			++i;
+			usleep_range(DA7218_ALC_CALIB_DELAY_MIN,
+				     DA7218_ALC_CALIB_DELAY_MAX);
+		} else {
+			calibrated = true;
+		}
+
+	} while ((i < DA7218_ALC_CALIB_MAX_TRIES) && (!calibrated));
+
+	/* If auto calibration fails, disable DC offset, hybrid ALC */
+	if ((!calibrated) || (calib_ctrl & DA7218_CALIB_OVERFLOW_MASK)) {
+		dev_warn(codec->dev,
+			 "ALC auto calibration failed - %s\n",
+			 (calibrated) ? "overflow" : "timeout");
+		snd_soc_update_bits(codec, DA7218_CALIB_CTRL,
+				    DA7218_CALIB_OFFSET_EN_MASK, 0);
+		snd_soc_update_bits(codec, DA7218_ALC_CTRL1,
+				    DA7218_ALC_SYNC_MODE_MASK, 0);
+
+	} else {
+		/* Enable DC offset cancellation */
+		snd_soc_update_bits(codec, DA7218_CALIB_CTRL,
+				    DA7218_CALIB_OFFSET_EN_MASK,
+				    DA7218_CALIB_OFFSET_EN_MASK);
+
+		/* Enable ALC hybrid mode */
+		snd_soc_update_bits(codec, DA7218_ALC_CTRL1,
+				    DA7218_ALC_SYNC_MODE_MASK,
+				    DA7218_ALC_SYNC_MODE_CH1 |
+				    DA7218_ALC_SYNC_MODE_CH2);
+	}
+
+	/* Restore input HPF control registers to original states */
+	snd_soc_write(codec, DA7218_IN_1_HPF_FILTER_CTRL, in_1_hpf_ctrl);
+	snd_soc_write(codec, DA7218_IN_2_HPF_FILTER_CTRL, in_2_hpf_ctrl);
+
+	/* Restore input filter control registers to original states */
+	snd_soc_write(codec, DA7218_IN_1L_FILTER_CTRL, in_1l_filt_ctrl);
+	snd_soc_write(codec, DA7218_IN_1R_FILTER_CTRL, in_1r_filt_ctrl);
+	snd_soc_write(codec, DA7218_IN_2L_FILTER_CTRL, in_2l_filt_ctrl);
+	snd_soc_write(codec, DA7218_IN_2R_FILTER_CTRL, in_2r_filt_ctrl);
+
+	/* Restore input mixer control registers to original state */
+	snd_soc_write(codec, DA7218_MIXIN_1_CTRL, mixin_1_ctrl);
+	snd_soc_write(codec, DA7218_MIXIN_2_CTRL, mixin_2_ctrl);
+
+	/* Restore MIC control registers to original states */
+	snd_soc_write(codec, DA7218_MIC_1_CTRL, mic_1_ctrl);
+	snd_soc_write(codec, DA7218_MIC_2_CTRL, mic_2_ctrl);
+}
+
+static int da7218_mixin_gain_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+	/*
+	 * If ALC in operation and value of control has been updated,
+	 * make sure calibrated offsets are updated.
+	 */
+	if ((ret == 1) && (da7218->alc_en))
+		da7218_alc_calib(codec);
+
+	return ret;
+}
+
+static int da7218_alc_sw_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *) kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	unsigned int lvalue = ucontrol->value.integer.value[0];
+	unsigned int rvalue = ucontrol->value.integer.value[1];
+	unsigned int lshift = mc->shift;
+	unsigned int rshift = mc->rshift;
+	unsigned int mask = (mc->max << lshift) | (mc->max << rshift);
+
+	/* Force ALC offset calibration if enabling ALC */
+	if ((lvalue || rvalue) && (!da7218->alc_en))
+		da7218_alc_calib(codec);
+
+	/* Update bits to detail which channels are enabled/disabled */
+	da7218->alc_en &= ~mask;
+	da7218->alc_en |= (lvalue << lshift) | (rvalue << rshift);
+
+	return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+/* ToneGen */
+static int da7218_tonegen_freq_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct soc_mixer_control *mixer_ctrl =
+		(struct soc_mixer_control *) kcontrol->private_value;
+	unsigned int reg = mixer_ctrl->reg;
+	u16 val;
+	int ret;
+
+	/*
+	 * Frequency value spans two 8-bit registers, lower then upper byte.
+	 * Therefore we need to convert to host endianness here.
+	 */
+	ret = regmap_raw_read(da7218->regmap, reg, &val, 2);
+	if (ret)
+		return ret;
+
+	ucontrol->value.integer.value[0] = le16_to_cpu(val);
+
+	return 0;
+}
+
+static int da7218_tonegen_freq_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct soc_mixer_control *mixer_ctrl =
+		(struct soc_mixer_control *) kcontrol->private_value;
+	unsigned int reg = mixer_ctrl->reg;
+	u16 val;
+
+	/*
+	 * Frequency value spans two 8-bit registers, lower then upper byte.
+	 * Therefore we need to convert to little endian here to align with
+	 * HW registers.
+	 */
+	val = cpu_to_le16(ucontrol->value.integer.value[0]);
+
+	return regmap_raw_write(da7218->regmap, reg, &val, 2);
+}
+
+static int da7218_mic_lvl_det_sw_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct soc_mixer_control *mixer_ctrl =
+		(struct soc_mixer_control *) kcontrol->private_value;
+	unsigned int lvalue = ucontrol->value.integer.value[0];
+	unsigned int rvalue = ucontrol->value.integer.value[1];
+	unsigned int lshift = mixer_ctrl->shift;
+	unsigned int rshift = mixer_ctrl->rshift;
+	unsigned int mask = (mixer_ctrl->max << lshift) |
+			    (mixer_ctrl->max << rshift);
+	da7218->mic_lvl_det_en &= ~mask;
+	da7218->mic_lvl_det_en |= (lvalue << lshift) | (rvalue << rshift);
+
+	/*
+	 * Here we only enable the feature on paths which are already
+	 * powered. If a channel is enabled here for level detect, but that path
+	 * isn't powered, then the channel will actually be enabled when we do
+	 * power the path (IN_FILTER widget events). This handling avoids
+	 * unwanted level detect events.
+	 */
+	return snd_soc_write(codec, mixer_ctrl->reg,
+			     (da7218->in_filt_en & da7218->mic_lvl_det_en));
+}
+
+static int da7218_mic_lvl_det_sw_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct soc_mixer_control *mixer_ctrl =
+		(struct soc_mixer_control *) kcontrol->private_value;
+	unsigned int lshift = mixer_ctrl->shift;
+	unsigned int rshift = mixer_ctrl->rshift;
+	unsigned int lmask = (mixer_ctrl->max << lshift);
+	unsigned int rmask = (mixer_ctrl->max << rshift);
+
+	ucontrol->value.integer.value[0] =
+		(da7218->mic_lvl_det_en & lmask) >> lshift;
+	ucontrol->value.integer.value[1] =
+		(da7218->mic_lvl_det_en & rmask) >> rshift;
+
+	return 0;
+}
+
+static int da7218_biquad_coeff_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct soc_bytes_ext *bytes_ext =
+		(struct soc_bytes_ext *) kcontrol->private_value;
+
+	/* Determine which BiQuads we're setting based on size of config data */
+	switch (bytes_ext->max) {
+	case DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE:
+		memcpy(ucontrol->value.bytes.data, da7218->biq_5stage_coeff,
+		       bytes_ext->max);
+		break;
+	case DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE:
+		memcpy(ucontrol->value.bytes.data, da7218->stbiq_3stage_coeff,
+		       bytes_ext->max);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int da7218_biquad_coeff_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct soc_bytes_ext *bytes_ext =
+		(struct soc_bytes_ext *) kcontrol->private_value;
+	u8 reg, out_filt1l;
+	u8 cfg[DA7218_BIQ_CFG_SIZE];
+	int i;
+
+	/*
+	 * Determine which BiQuads we're setting based on size of config data,
+	 * and stored the data for use by get function.
+	 */
+	switch (bytes_ext->max) {
+	case DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE:
+		reg = DA7218_OUT_1_BIQ_5STAGE_DATA;
+		memcpy(da7218->biq_5stage_coeff, ucontrol->value.bytes.data,
+		       bytes_ext->max);
+		break;
+	case DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE:
+		reg = DA7218_SIDETONE_BIQ_3STAGE_DATA;
+		memcpy(da7218->stbiq_3stage_coeff, ucontrol->value.bytes.data,
+		       bytes_ext->max);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Make sure at least out filter1 enabled to allow programming */
+	out_filt1l = snd_soc_read(codec, DA7218_OUT_1L_FILTER_CTRL);
+	snd_soc_write(codec, DA7218_OUT_1L_FILTER_CTRL,
+		      out_filt1l | DA7218_OUT_1L_FILTER_EN_MASK);
+
+	for (i = 0; i < bytes_ext->max; ++i) {
+		cfg[DA7218_BIQ_CFG_DATA] = ucontrol->value.bytes.data[i];
+		cfg[DA7218_BIQ_CFG_ADDR] = i;
+		regmap_raw_write(da7218->regmap, reg, cfg, DA7218_BIQ_CFG_SIZE);
+	}
+
+	/* Restore filter to previous setting */
+	snd_soc_write(codec, DA7218_OUT_1L_FILTER_CTRL, out_filt1l);
+
+	return 0;
+}
+
+
+/*
+ * KControls
+ */
+
+static const struct snd_kcontrol_new da7218_snd_controls[] = {
+	/* Mics */
+	SOC_SINGLE_TLV("Mic1 Volume", DA7218_MIC_1_GAIN,
+		       DA7218_MIC_1_AMP_GAIN_SHIFT, DA7218_MIC_AMP_GAIN_MAX,
+		       DA7218_NO_INVERT, da7218_mic_gain_tlv),
+	SOC_SINGLE("Mic1 Switch", DA7218_MIC_1_CTRL,
+		   DA7218_MIC_1_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+	SOC_SINGLE_TLV("Mic2 Volume", DA7218_MIC_2_GAIN,
+		       DA7218_MIC_2_AMP_GAIN_SHIFT, DA7218_MIC_AMP_GAIN_MAX,
+		       DA7218_NO_INVERT, da7218_mic_gain_tlv),
+	SOC_SINGLE("Mic2 Switch", DA7218_MIC_2_CTRL,
+		   DA7218_MIC_2_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+
+	/* Mixer Input */
+	SOC_SINGLE_EXT_TLV("Mixin1 Volume", DA7218_MIXIN_1_GAIN,
+			   DA7218_MIXIN_1_AMP_GAIN_SHIFT,
+			   DA7218_MIXIN_AMP_GAIN_MAX, DA7218_NO_INVERT,
+			   snd_soc_get_volsw, da7218_mixin_gain_put,
+			   da7218_mixin_gain_tlv),
+	SOC_SINGLE("Mixin1 Switch", DA7218_MIXIN_1_CTRL,
+		   DA7218_MIXIN_1_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+	SOC_SINGLE("Mixin1 Gain Ramp Switch", DA7218_MIXIN_1_CTRL,
+		   DA7218_MIXIN_1_AMP_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("Mixin1 ZC Gain Switch", DA7218_MIXIN_1_CTRL,
+		   DA7218_MIXIN_1_AMP_ZC_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE_EXT_TLV("Mixin2 Volume", DA7218_MIXIN_2_GAIN,
+			   DA7218_MIXIN_2_AMP_GAIN_SHIFT,
+			   DA7218_MIXIN_AMP_GAIN_MAX, DA7218_NO_INVERT,
+			   snd_soc_get_volsw, da7218_mixin_gain_put,
+			   da7218_mixin_gain_tlv),
+	SOC_SINGLE("Mixin2 Switch", DA7218_MIXIN_2_CTRL,
+		   DA7218_MIXIN_2_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+	SOC_SINGLE("Mixin2 Gain Ramp Switch", DA7218_MIXIN_2_CTRL,
+		   DA7218_MIXIN_2_AMP_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("Mixin2 ZC Gain Switch", DA7218_MIXIN_2_CTRL,
+		   DA7218_MIXIN_2_AMP_ZC_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+
+	/* ADCs */
+	SOC_SINGLE("ADC1 AAF Switch", DA7218_ADC_1_CTRL,
+		   DA7218_ADC_1_AAF_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("ADC2 AAF Switch", DA7218_ADC_2_CTRL,
+		   DA7218_ADC_2_AAF_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("ADC LP Mode Switch", DA7218_ADC_MODE,
+		   DA7218_ADC_LP_MODE_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+
+	/* Input Filters */
+	SOC_SINGLE_TLV("In Filter1L Volume", DA7218_IN_1L_GAIN,
+		       DA7218_IN_1L_DIGITAL_GAIN_SHIFT,
+		       DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_in_dig_gain_tlv),
+	SOC_SINGLE("In Filter1L Switch", DA7218_IN_1L_FILTER_CTRL,
+		   DA7218_IN_1L_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+	SOC_SINGLE("In Filter1L Gain Ramp Switch", DA7218_IN_1L_FILTER_CTRL,
+		   DA7218_IN_1L_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE_TLV("In Filter1R Volume", DA7218_IN_1R_GAIN,
+		       DA7218_IN_1R_DIGITAL_GAIN_SHIFT,
+		       DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_in_dig_gain_tlv),
+	SOC_SINGLE("In Filter1R Switch", DA7218_IN_1R_FILTER_CTRL,
+		   DA7218_IN_1R_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+	SOC_SINGLE("In Filter1R Gain Ramp Switch",
+		   DA7218_IN_1R_FILTER_CTRL, DA7218_IN_1R_RAMP_EN_SHIFT,
+		   DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+	SOC_SINGLE_TLV("In Filter2L Volume", DA7218_IN_2L_GAIN,
+		       DA7218_IN_2L_DIGITAL_GAIN_SHIFT,
+		       DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_in_dig_gain_tlv),
+	SOC_SINGLE("In Filter2L Switch", DA7218_IN_2L_FILTER_CTRL,
+		   DA7218_IN_2L_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+	SOC_SINGLE("In Filter2L Gain Ramp Switch", DA7218_IN_2L_FILTER_CTRL,
+		   DA7218_IN_2L_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE_TLV("In Filter2R Volume", DA7218_IN_2R_GAIN,
+		       DA7218_IN_2R_DIGITAL_GAIN_SHIFT,
+		       DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_in_dig_gain_tlv),
+	SOC_SINGLE("In Filter2R Switch", DA7218_IN_2R_FILTER_CTRL,
+		   DA7218_IN_2R_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+	SOC_SINGLE("In Filter2R Gain Ramp Switch",
+		   DA7218_IN_2R_FILTER_CTRL, DA7218_IN_2R_RAMP_EN_SHIFT,
+		   DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+
+	/* AGS */
+	SOC_SINGLE_TLV("AGS Trigger", DA7218_AGS_TRIGGER,
+		       DA7218_AGS_TRIGGER_SHIFT, DA7218_AGS_TRIGGER_MAX,
+		       DA7218_INVERT, da7218_ags_trigger_tlv),
+	SOC_SINGLE_TLV("AGS Max Attenuation", DA7218_AGS_ATT_MAX,
+		       DA7218_AGS_ATT_MAX_SHIFT, DA7218_AGS_ATT_MAX_MAX,
+		       DA7218_NO_INVERT, da7218_ags_att_max_tlv),
+	SOC_SINGLE("AGS Anticlip Switch", DA7218_AGS_ANTICLIP_CTRL,
+		   DA7218_AGS_ANTICLIP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("AGS Channel1 Switch", DA7218_AGS_ENABLE,
+		   DA7218_AGS_ENABLE_CHAN1_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("AGS Channel2 Switch", DA7218_AGS_ENABLE,
+		   DA7218_AGS_ENABLE_CHAN2_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+
+	/* ALC */
+	SOC_ENUM("ALC Attack Rate", da7218_alc_attack_rate),
+	SOC_ENUM("ALC Release Rate", da7218_alc_release_rate),
+	SOC_ENUM("ALC Hold Time", da7218_alc_hold_time),
+	SOC_SINGLE_TLV("ALC Noise Threshold", DA7218_ALC_NOISE,
+		       DA7218_ALC_NOISE_SHIFT, DA7218_ALC_THRESHOLD_MAX,
+		       DA7218_INVERT, da7218_alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Min Threshold", DA7218_ALC_TARGET_MIN,
+		       DA7218_ALC_THRESHOLD_MIN_SHIFT, DA7218_ALC_THRESHOLD_MAX,
+		       DA7218_INVERT, da7218_alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Max Threshold", DA7218_ALC_TARGET_MAX,
+		       DA7218_ALC_THRESHOLD_MAX_SHIFT, DA7218_ALC_THRESHOLD_MAX,
+		       DA7218_INVERT, da7218_alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Max Attenuation", DA7218_ALC_GAIN_LIMITS,
+		       DA7218_ALC_ATTEN_MAX_SHIFT, DA7218_ALC_ATTEN_GAIN_MAX,
+		       DA7218_NO_INVERT, da7218_alc_gain_tlv),
+	SOC_SINGLE_TLV("ALC Max Gain", DA7218_ALC_GAIN_LIMITS,
+		       DA7218_ALC_GAIN_MAX_SHIFT, DA7218_ALC_ATTEN_GAIN_MAX,
+		       DA7218_NO_INVERT, da7218_alc_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("ALC Min Analog Gain", DA7218_ALC_ANA_GAIN_LIMITS,
+			     DA7218_ALC_ANA_GAIN_MIN_SHIFT,
+			     DA7218_ALC_ANA_GAIN_MIN, DA7218_ALC_ANA_GAIN_MAX,
+			     DA7218_NO_INVERT, da7218_alc_ana_gain_tlv),
+	SOC_SINGLE_RANGE_TLV("ALC Max Analog Gain", DA7218_ALC_ANA_GAIN_LIMITS,
+			     DA7218_ALC_ANA_GAIN_MAX_SHIFT,
+			     DA7218_ALC_ANA_GAIN_MIN, DA7218_ALC_ANA_GAIN_MAX,
+			     DA7218_NO_INVERT, da7218_alc_ana_gain_tlv),
+	SOC_ENUM("ALC Anticlip Step", da7218_alc_anticlip_step),
+	SOC_SINGLE("ALC Anticlip Switch", DA7218_ALC_ANTICLIP_CTRL,
+		   DA7218_ALC_ANTICLIP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_DOUBLE_EXT("ALC Channel1 Switch", DA7218_ALC_CTRL1,
+		       DA7218_ALC_CHAN1_L_EN_SHIFT, DA7218_ALC_CHAN1_R_EN_SHIFT,
+		       DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT,
+		       snd_soc_get_volsw, da7218_alc_sw_put),
+	SOC_DOUBLE_EXT("ALC Channel2 Switch", DA7218_ALC_CTRL1,
+		       DA7218_ALC_CHAN2_L_EN_SHIFT, DA7218_ALC_CHAN2_R_EN_SHIFT,
+		       DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT,
+		       snd_soc_get_volsw, da7218_alc_sw_put),
+
+	/* Envelope Tracking */
+	SOC_ENUM("Envelope Tracking Attack Rate", da7218_integ_attack_rate),
+	SOC_ENUM("Envelope Tracking Release Rate", da7218_integ_release_rate),
+
+	/* Input High-Pass Filters */
+	SOC_ENUM("In Filter1 HPF Mode", da7218_in1_hpf_mode),
+	SOC_ENUM("In Filter1 HPF Corner Audio", da7218_in1_audio_hpf_corner),
+	SOC_ENUM("In Filter1 HPF Corner Voice", da7218_in1_voice_hpf_corner),
+	SOC_ENUM("In Filter2 HPF Mode", da7218_in2_hpf_mode),
+	SOC_ENUM("In Filter2 HPF Corner Audio", da7218_in2_audio_hpf_corner),
+	SOC_ENUM("In Filter2 HPF Corner Voice", da7218_in2_voice_hpf_corner),
+
+	/* Mic Level Detect */
+	SOC_DOUBLE_EXT("Mic Level Detect Channel1 Switch", DA7218_LVL_DET_CTRL,
+		       DA7218_LVL_DET_EN_CHAN1L_SHIFT,
+		       DA7218_LVL_DET_EN_CHAN1R_SHIFT, DA7218_SWITCH_EN_MAX,
+		       DA7218_NO_INVERT, da7218_mic_lvl_det_sw_get,
+		       da7218_mic_lvl_det_sw_put),
+	SOC_DOUBLE_EXT("Mic Level Detect Channel2 Switch", DA7218_LVL_DET_CTRL,
+		       DA7218_LVL_DET_EN_CHAN2L_SHIFT,
+		       DA7218_LVL_DET_EN_CHAN2R_SHIFT, DA7218_SWITCH_EN_MAX,
+		       DA7218_NO_INVERT, da7218_mic_lvl_det_sw_get,
+		       da7218_mic_lvl_det_sw_put),
+	SOC_SINGLE("Mic Level Detect Level", DA7218_LVL_DET_LEVEL,
+		   DA7218_LVL_DET_LEVEL_SHIFT, DA7218_LVL_DET_LEVEL_MAX,
+		   DA7218_NO_INVERT),
+
+	/* Digital Mixer (Input) */
+	SOC_SINGLE_TLV("DMix In Filter1L Out1 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN,
+		       DA7218_OUTDAI_1L_INFILT_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1L Out1 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN,
+		       DA7218_OUTDAI_1R_INFILT_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1L Out2 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN,
+		       DA7218_OUTDAI_2L_INFILT_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1L Out2 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN,
+		       DA7218_OUTDAI_2R_INFILT_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In Filter1R Out1 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN,
+		       DA7218_OUTDAI_1L_INFILT_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1R Out1 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN,
+		       DA7218_OUTDAI_1R_INFILT_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1R Out2 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN,
+		       DA7218_OUTDAI_2L_INFILT_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1R Out2 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN,
+		       DA7218_OUTDAI_2R_INFILT_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In Filter2L Out1 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN,
+		       DA7218_OUTDAI_1L_INFILT_2L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2L Out1 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN,
+		       DA7218_OUTDAI_1R_INFILT_2L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2L Out2 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN,
+		       DA7218_OUTDAI_2L_INFILT_2L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2L Out2 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN,
+		       DA7218_OUTDAI_2R_INFILT_2L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In Filter2R Out1 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN,
+		       DA7218_OUTDAI_1L_INFILT_2R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2R Out1 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN,
+		       DA7218_OUTDAI_1R_INFILT_2R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2R Out2 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN,
+		       DA7218_OUTDAI_2L_INFILT_2R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2R Out2 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN,
+		       DA7218_OUTDAI_2R_INFILT_2R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix ToneGen Out1 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN,
+		       DA7218_OUTDAI_1L_TONEGEN_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix ToneGen Out1 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN,
+		       DA7218_OUTDAI_1R_TONEGEN_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix ToneGen Out2 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN,
+		       DA7218_OUTDAI_2L_TONEGEN_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix ToneGen Out2 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN,
+		       DA7218_OUTDAI_2R_TONEGEN_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In DAIL Out1 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN,
+		       DA7218_OUTDAI_1L_INDAI_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIL Out1 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN,
+		       DA7218_OUTDAI_1R_INDAI_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIL Out2 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN,
+		       DA7218_OUTDAI_2L_INDAI_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIL Out2 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN,
+		       DA7218_OUTDAI_2R_INDAI_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In DAIR Out1 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN,
+		       DA7218_OUTDAI_1L_INDAI_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIR Out1 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN,
+		       DA7218_OUTDAI_1R_INDAI_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIR Out2 DAIL Volume",
+		       DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN,
+		       DA7218_OUTDAI_2L_INDAI_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIR Out2 DAIR Volume",
+		       DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN,
+		       DA7218_OUTDAI_2R_INDAI_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	/* Digital Mixer (Output) */
+	SOC_SINGLE_TLV("DMix In Filter1L Out FilterL Volume",
+		       DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN,
+		       DA7218_OUTFILT_1L_INFILT_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1L Out FilterR Volume",
+		       DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN,
+		       DA7218_OUTFILT_1R_INFILT_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In Filter1R Out FilterL Volume",
+		       DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN,
+		       DA7218_OUTFILT_1L_INFILT_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter1R Out FilterR Volume",
+		       DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN,
+		       DA7218_OUTFILT_1R_INFILT_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In Filter2L Out FilterL Volume",
+		       DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN,
+		       DA7218_OUTFILT_1L_INFILT_2L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2L Out FilterR Volume",
+		       DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN,
+		       DA7218_OUTFILT_1R_INFILT_2L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In Filter2R Out FilterL Volume",
+		       DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN,
+		       DA7218_OUTFILT_1L_INFILT_2R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In Filter2R Out FilterR Volume",
+		       DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN,
+		       DA7218_OUTFILT_1R_INFILT_2R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix ToneGen Out FilterL Volume",
+		       DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN,
+		       DA7218_OUTFILT_1L_TONEGEN_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix ToneGen Out FilterR Volume",
+		       DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN,
+		       DA7218_OUTFILT_1R_TONEGEN_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In DAIL Out FilterL Volume",
+		       DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN,
+		       DA7218_OUTFILT_1L_INDAI_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIL Out FilterR Volume",
+		       DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN,
+		       DA7218_OUTFILT_1R_INDAI_1L_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	SOC_SINGLE_TLV("DMix In DAIR Out FilterL Volume",
+		       DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN,
+		       DA7218_OUTFILT_1L_INDAI_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+	SOC_SINGLE_TLV("DMix In DAIR Out FilterR Volume",
+		       DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN,
+		       DA7218_OUTFILT_1R_INDAI_1R_GAIN_SHIFT,
+		       DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT,
+		       da7218_dmix_gain_tlv),
+
+	/* Sidetone Filter */
+	SND_SOC_BYTES_EXT("Sidetone BiQuad Coefficients",
+			  DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE,
+			  da7218_biquad_coeff_get, da7218_biquad_coeff_put),
+	SOC_SINGLE_TLV("Sidetone Volume", DA7218_SIDETONE_GAIN,
+		       DA7218_SIDETONE_GAIN_SHIFT, DA7218_DMIX_GAIN_MAX,
+		       DA7218_NO_INVERT, da7218_dmix_gain_tlv),
+	SOC_SINGLE("Sidetone Switch", DA7218_SIDETONE_CTRL,
+		   DA7218_SIDETONE_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+
+	/* Tone Generator */
+	SOC_ENUM("ToneGen DTMF Key", da7218_tonegen_dtmf_key),
+	SOC_SINGLE("ToneGen DTMF Switch", DA7218_TONE_GEN_CFG1,
+		   DA7218_DTMF_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_ENUM("ToneGen Sinewave Gen Type", da7218_tonegen_swg_sel),
+	SOC_SINGLE_EXT("ToneGen Sinewave1 Freq", DA7218_TONE_GEN_FREQ1_L,
+		       DA7218_FREQ1_L_SHIFT, DA7218_FREQ_MAX, DA7218_NO_INVERT,
+		       da7218_tonegen_freq_get, da7218_tonegen_freq_put),
+	SOC_SINGLE_EXT("ToneGen Sinewave2 Freq", DA7218_TONE_GEN_FREQ2_L,
+		       DA7218_FREQ2_L_SHIFT, DA7218_FREQ_MAX, DA7218_NO_INVERT,
+		       da7218_tonegen_freq_get, da7218_tonegen_freq_put),
+	SOC_SINGLE("ToneGen On Time", DA7218_TONE_GEN_ON_PER,
+		   DA7218_BEEP_ON_PER_SHIFT, DA7218_BEEP_ON_OFF_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("ToneGen Off Time", DA7218_TONE_GEN_OFF_PER,
+		   DA7218_BEEP_OFF_PER_SHIFT, DA7218_BEEP_ON_OFF_MAX,
+		   DA7218_NO_INVERT),
+
+	/* Gain ramping */
+	SOC_ENUM("Gain Ramp Rate", da7218_gain_ramp_rate),
+
+	/* DGS */
+	SOC_SINGLE_TLV("DGS Trigger", DA7218_DGS_TRIGGER,
+		       DA7218_DGS_TRIGGER_LVL_SHIFT, DA7218_DGS_TRIGGER_MAX,
+		       DA7218_INVERT, da7218_dgs_trigger_tlv),
+	SOC_ENUM("DGS Rise Coefficient", da7218_dgs_rise_coeff),
+	SOC_ENUM("DGS Fall Coefficient", da7218_dgs_fall_coeff),
+	SOC_SINGLE("DGS Sync Delay", DA7218_DGS_SYNC_DELAY,
+		   DA7218_DGS_SYNC_DELAY_SHIFT, DA7218_DGS_SYNC_DELAY_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("DGS Fast SR Sync Delay", DA7218_DGS_SYNC_DELAY2,
+		   DA7218_DGS_SYNC_DELAY2_SHIFT, DA7218_DGS_SYNC_DELAY_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("DGS Voice Filter Sync Delay", DA7218_DGS_SYNC_DELAY3,
+		   DA7218_DGS_SYNC_DELAY3_SHIFT, DA7218_DGS_SYNC_DELAY3_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE_TLV("DGS Anticlip Level", DA7218_DGS_LEVELS,
+		       DA7218_DGS_ANTICLIP_LVL_SHIFT,
+		       DA7218_DGS_ANTICLIP_LVL_MAX, DA7218_INVERT,
+		       da7218_dgs_anticlip_tlv),
+	SOC_SINGLE_TLV("DGS Signal Level", DA7218_DGS_LEVELS,
+		       DA7218_DGS_SIGNAL_LVL_SHIFT, DA7218_DGS_SIGNAL_LVL_MAX,
+		       DA7218_INVERT, da7218_dgs_signal_tlv),
+	SOC_SINGLE("DGS Gain Subrange Switch", DA7218_DGS_GAIN_CTRL,
+		   DA7218_DGS_SUBR_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("DGS Gain Ramp Switch", DA7218_DGS_GAIN_CTRL,
+		   DA7218_DGS_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+	SOC_SINGLE("DGS Gain Steps", DA7218_DGS_GAIN_CTRL,
+		   DA7218_DGS_STEPS_SHIFT, DA7218_DGS_STEPS_MAX,
+		   DA7218_NO_INVERT),
+	SOC_DOUBLE("DGS Switch", DA7218_DGS_ENABLE, DA7218_DGS_ENABLE_L_SHIFT,
+		   DA7218_DGS_ENABLE_R_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+
+	/* Output High-Pass Filter */
+	SOC_ENUM("Out Filter HPF Mode", da7218_out1_hpf_mode),
+	SOC_ENUM("Out Filter HPF Corner Audio", da7218_out1_audio_hpf_corner),
+	SOC_ENUM("Out Filter HPF Corner Voice", da7218_out1_voice_hpf_corner),
+
+	/* 5-Band Equaliser */
+	SOC_SINGLE_TLV("Out EQ Band1 Volume", DA7218_OUT_1_EQ_12_FILTER_CTRL,
+		       DA7218_OUT_1_EQ_BAND1_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+		       DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+	SOC_SINGLE_TLV("Out EQ Band2 Volume", DA7218_OUT_1_EQ_12_FILTER_CTRL,
+		       DA7218_OUT_1_EQ_BAND2_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+		       DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+	SOC_SINGLE_TLV("Out EQ Band3 Volume", DA7218_OUT_1_EQ_34_FILTER_CTRL,
+		       DA7218_OUT_1_EQ_BAND3_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+		       DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+	SOC_SINGLE_TLV("Out EQ Band4 Volume", DA7218_OUT_1_EQ_34_FILTER_CTRL,
+		       DA7218_OUT_1_EQ_BAND4_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+		       DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+	SOC_SINGLE_TLV("Out EQ Band5 Volume", DA7218_OUT_1_EQ_5_FILTER_CTRL,
+		       DA7218_OUT_1_EQ_BAND5_SHIFT, DA7218_OUT_EQ_BAND_MAX,
+		       DA7218_NO_INVERT, da7218_out_eq_band_tlv),
+	SOC_SINGLE("Out EQ Switch", DA7218_OUT_1_EQ_5_FILTER_CTRL,
+		   DA7218_OUT_1_EQ_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_NO_INVERT),
+
+	/* BiQuad Filters */
+	SND_SOC_BYTES_EXT("BiQuad Coefficients",
+			  DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE,
+			  da7218_biquad_coeff_get, da7218_biquad_coeff_put),
+	SOC_SINGLE("BiQuad Filter Switch", DA7218_OUT_1_BIQ_5STAGE_CTRL,
+		   DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		   DA7218_INVERT),
+
+	/* Output Filters */
+	SOC_DOUBLE_R_RANGE_TLV("Out Filter Volume", DA7218_OUT_1L_GAIN,
+			       DA7218_OUT_1R_GAIN,
+			       DA7218_OUT_1L_DIGITAL_GAIN_SHIFT,
+			       DA7218_OUT_DIGITAL_GAIN_MIN,
+			       DA7218_OUT_DIGITAL_GAIN_MAX, DA7218_NO_INVERT,
+			       da7218_out_dig_gain_tlv),
+	SOC_DOUBLE_R("Out Filter Switch", DA7218_OUT_1L_FILTER_CTRL,
+		     DA7218_OUT_1R_FILTER_CTRL, DA7218_OUT_1L_MUTE_EN_SHIFT,
+		     DA7218_SWITCH_EN_MAX, DA7218_INVERT),
+	SOC_DOUBLE_R("Out Filter Gain Subrange Switch",
+		     DA7218_OUT_1L_FILTER_CTRL, DA7218_OUT_1R_FILTER_CTRL,
+		     DA7218_OUT_1L_SUBRANGE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		     DA7218_NO_INVERT),
+	SOC_DOUBLE_R("Out Filter Gain Ramp Switch", DA7218_OUT_1L_FILTER_CTRL,
+		     DA7218_OUT_1R_FILTER_CTRL, DA7218_OUT_1L_RAMP_EN_SHIFT,
+		     DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+
+	/* Mixer Output */
+	SOC_DOUBLE_R_RANGE_TLV("Mixout Volume", DA7218_MIXOUT_L_GAIN,
+			       DA7218_MIXOUT_R_GAIN,
+			       DA7218_MIXOUT_L_AMP_GAIN_SHIFT,
+			       DA7218_MIXOUT_AMP_GAIN_MIN,
+			       DA7218_MIXOUT_AMP_GAIN_MAX, DA7218_NO_INVERT,
+			       da7218_mixout_gain_tlv),
+
+	/* DAC Noise Gate */
+	SOC_ENUM("DAC NG Setup Time", da7218_dac_ng_setup_time),
+	SOC_ENUM("DAC NG Rampup Rate", da7218_dac_ng_rampup_rate),
+	SOC_ENUM("DAC NG Rampdown Rate", da7218_dac_ng_rampdown_rate),
+	SOC_SINGLE_TLV("DAC NG Off Threshold", DA7218_DAC_NG_OFF_THRESH,
+		       DA7218_DAC_NG_OFF_THRESHOLD_SHIFT,
+		       DA7218_DAC_NG_THRESHOLD_MAX, DA7218_NO_INVERT,
+		       da7218_dac_ng_threshold_tlv),
+	SOC_SINGLE_TLV("DAC NG On Threshold", DA7218_DAC_NG_ON_THRESH,
+		       DA7218_DAC_NG_ON_THRESHOLD_SHIFT,
+		       DA7218_DAC_NG_THRESHOLD_MAX, DA7218_NO_INVERT,
+		       da7218_dac_ng_threshold_tlv),
+	SOC_SINGLE("DAC NG Switch", DA7218_DAC_NG_CTRL, DA7218_DAC_NG_EN_SHIFT,
+		   DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+
+	/* CP */
+	SOC_ENUM("Charge Pump Track Mode", da7218_cp_mchange),
+	SOC_ENUM("Charge Pump Frequency", da7218_cp_fcontrol),
+	SOC_ENUM("Charge Pump Decay Rate", da7218_cp_tau_delay),
+	SOC_SINGLE("Charge Pump Threshold", DA7218_CP_VOL_THRESHOLD1,
+		   DA7218_CP_THRESH_VDD2_SHIFT, DA7218_CP_THRESH_VDD2_MAX,
+		   DA7218_NO_INVERT),
+
+	/* Headphones */
+	SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", DA7218_HP_L_GAIN,
+			       DA7218_HP_R_GAIN, DA7218_HP_L_AMP_GAIN_SHIFT,
+			       DA7218_HP_AMP_GAIN_MIN, DA7218_HP_AMP_GAIN_MAX,
+			       DA7218_NO_INVERT, da7218_hp_gain_tlv),
+	SOC_DOUBLE_R("Headphone Switch", DA7218_HP_L_CTRL, DA7218_HP_R_CTRL,
+		     DA7218_HP_L_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX,
+		     DA7218_INVERT),
+	SOC_DOUBLE_R("Headphone Gain Ramp Switch", DA7218_HP_L_CTRL,
+		     DA7218_HP_R_CTRL, DA7218_HP_L_AMP_RAMP_EN_SHIFT,
+		     DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+	SOC_DOUBLE_R("Headphone ZC Gain Switch", DA7218_HP_L_CTRL,
+		     DA7218_HP_R_CTRL, DA7218_HP_L_AMP_ZC_EN_SHIFT,
+		     DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),
+};
+
+
+/*
+ * DAPM Mux Controls
+ */
+
+static const char * const da7218_mic_sel_text[] = { "Analog", "Digital" };
+
+static const struct soc_enum da7218_mic1_sel =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(da7218_mic_sel_text),
+			    da7218_mic_sel_text);
+
+static const struct snd_kcontrol_new da7218_mic1_sel_mux =
+	SOC_DAPM_ENUM("Mic1 Mux", da7218_mic1_sel);
+
+static const struct soc_enum da7218_mic2_sel =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(da7218_mic_sel_text),
+			    da7218_mic_sel_text);
+
+static const struct snd_kcontrol_new da7218_mic2_sel_mux =
+	SOC_DAPM_ENUM("Mic2 Mux", da7218_mic2_sel);
+
+static const char * const da7218_sidetone_in_sel_txt[] = {
+	"In Filter1L", "In Filter1R", "In Filter2L", "In Filter2R"
+};
+
+static const struct soc_enum da7218_sidetone_in_sel =
+	SOC_ENUM_SINGLE(DA7218_SIDETONE_IN_SELECT,
+			DA7218_SIDETONE_IN_SELECT_SHIFT,
+			DA7218_SIDETONE_IN_SELECT_MAX,
+			da7218_sidetone_in_sel_txt);
+
+static const struct snd_kcontrol_new da7218_sidetone_in_sel_mux =
+	SOC_DAPM_ENUM("Sidetone Mux", da7218_sidetone_in_sel);
+
+static const char * const da7218_out_filt_biq_sel_txt[] = {
+	"Bypass", "Enabled"
+};
+
+static const struct soc_enum da7218_out_filtl_biq_sel =
+	SOC_ENUM_SINGLE(DA7218_OUT_1L_FILTER_CTRL,
+			DA7218_OUT_1L_BIQ_5STAGE_SEL_SHIFT,
+			DA7218_OUT_BIQ_5STAGE_SEL_MAX,
+			da7218_out_filt_biq_sel_txt);
+
+static const struct snd_kcontrol_new da7218_out_filtl_biq_sel_mux =
+	SOC_DAPM_ENUM("Out FilterL BiQuad Mux", da7218_out_filtl_biq_sel);
+
+static const struct soc_enum da7218_out_filtr_biq_sel =
+	SOC_ENUM_SINGLE(DA7218_OUT_1R_FILTER_CTRL,
+			DA7218_OUT_1R_BIQ_5STAGE_SEL_SHIFT,
+			DA7218_OUT_BIQ_5STAGE_SEL_MAX,
+			da7218_out_filt_biq_sel_txt);
+
+static const struct snd_kcontrol_new da7218_out_filtr_biq_sel_mux =
+	SOC_DAPM_ENUM("Out FilterR BiQuad Mux", da7218_out_filtr_biq_sel);
+
+
+/*
+ * DAPM Mixer Controls
+ */
+
+#define DA7218_DMIX_CTRLS(reg)						\
+	SOC_DAPM_SINGLE("In Filter1L Switch", reg,			\
+			DA7218_DMIX_SRC_INFILT1L,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("In Filter1R Switch", reg,			\
+			DA7218_DMIX_SRC_INFILT1R,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("In Filter2L Switch", reg,			\
+			DA7218_DMIX_SRC_INFILT2L,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("In Filter2R Switch", reg,			\
+			DA7218_DMIX_SRC_INFILT2R,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("ToneGen Switch", reg,				\
+			DA7218_DMIX_SRC_TONEGEN,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("DAIL Switch", reg, DA7218_DMIX_SRC_DAIL,	\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("DAIR Switch", reg, DA7218_DMIX_SRC_DAIR,	\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT)
+
+static const struct snd_kcontrol_new da7218_out_dai1l_mix_controls[] = {
+	DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_1L),
+};
+
+static const struct snd_kcontrol_new da7218_out_dai1r_mix_controls[] = {
+	DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_1R),
+};
+
+static const struct snd_kcontrol_new da7218_out_dai2l_mix_controls[] = {
+	DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_2L),
+};
+
+static const struct snd_kcontrol_new da7218_out_dai2r_mix_controls[] = {
+	DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_2R),
+};
+
+static const struct snd_kcontrol_new da7218_out_filtl_mix_controls[] = {
+	DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTFILT_1L),
+};
+
+static const struct snd_kcontrol_new da7218_out_filtr_mix_controls[] = {
+	DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTFILT_1R),
+};
+
+#define DA7218_DMIX_ST_CTRLS(reg)					\
+	SOC_DAPM_SINGLE("Out FilterL Switch", reg,			\
+			DA7218_DMIX_ST_SRC_OUTFILT1L,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("Out FilterR Switch", reg,			\
+			DA7218_DMIX_ST_SRC_OUTFILT1R,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT),	\
+	SOC_DAPM_SINGLE("Sidetone Switch", reg,				\
+			DA7218_DMIX_ST_SRC_SIDETONE,			\
+			DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT)		\
+
+static const struct snd_kcontrol_new da7218_st_out_filtl_mix_controls[] = {
+	DA7218_DMIX_ST_CTRLS(DA7218_DROUTING_ST_OUTFILT_1L),
+};
+
+static const struct snd_kcontrol_new da7218_st_out_filtr_mix_controls[] = {
+	DA7218_DMIX_ST_CTRLS(DA7218_DROUTING_ST_OUTFILT_1R),
+};
+
+
+/*
+ * DAPM Events
+ */
+
+/*
+ * We keep track of which input filters are enabled. This is used in the logic
+ * for controlling the mic level detect feature.
+ */
+static int da7218_in_filter_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 da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	u8 mask;
+
+	switch (w->reg) {
+	case DA7218_IN_1L_FILTER_CTRL:
+		mask = (1 << DA7218_LVL_DET_EN_CHAN1L_SHIFT);
+		break;
+	case DA7218_IN_1R_FILTER_CTRL:
+		mask = (1 << DA7218_LVL_DET_EN_CHAN1R_SHIFT);
+		break;
+	case DA7218_IN_2L_FILTER_CTRL:
+		mask = (1 << DA7218_LVL_DET_EN_CHAN2L_SHIFT);
+		break;
+	case DA7218_IN_2R_FILTER_CTRL:
+		mask = (1 << DA7218_LVL_DET_EN_CHAN2R_SHIFT);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		da7218->in_filt_en |= mask;
+		/*
+		 * If we're enabling path for mic level detect, wait for path
+		 * to settle before enabling feature to avoid incorrect and
+		 * unwanted detect events.
+		 */
+		if (mask & da7218->mic_lvl_det_en)
+			msleep(DA7218_MIC_LVL_DET_DELAY);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		da7218->in_filt_en &= ~mask;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Enable configured level detection paths */
+	snd_soc_write(codec, DA7218_LVL_DET_CTRL,
+		      (da7218->in_filt_en & da7218->mic_lvl_det_en));
+
+	return 0;
+}
+
+static int da7218_dai_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 da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	u8 pll_ctrl, pll_status, refosc_cal;
+	int i;
+	bool success;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (da7218->master)
+			/* Enable DAI clks for master mode */
+			snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+					    DA7218_DAI_CLK_EN_MASK,
+					    DA7218_DAI_CLK_EN_MASK);
+
+		/* Tune reference oscillator */
+		snd_soc_write(codec, DA7218_PLL_REFOSC_CAL,
+			      DA7218_PLL_REFOSC_CAL_START_MASK);
+		snd_soc_write(codec, DA7218_PLL_REFOSC_CAL,
+			      DA7218_PLL_REFOSC_CAL_START_MASK |
+			      DA7218_PLL_REFOSC_CAL_EN_MASK);
+
+		/* Check tuning complete */
+		i = 0;
+		success = false;
+		do {
+			refosc_cal = snd_soc_read(codec, DA7218_PLL_REFOSC_CAL);
+			if (!(refosc_cal & DA7218_PLL_REFOSC_CAL_START_MASK)) {
+				success = true;
+			} else {
+				++i;
+				usleep_range(DA7218_REF_OSC_CHECK_DELAY_MIN,
+					     DA7218_REF_OSC_CHECK_DELAY_MAX);
+			}
+		} while ((i < DA7218_REF_OSC_CHECK_TRIES) && (!success));
+
+		if (!success)
+			dev_warn(codec->dev,
+				 "Reference oscillator failed calibration\n");
+
+		/* PC synchronised to DAI */
+		snd_soc_write(codec, DA7218_PC_COUNT,
+			      DA7218_PC_RESYNC_AUTO_MASK);
+
+		/* If SRM not enabled, we don't need to check status */
+		pll_ctrl = snd_soc_read(codec, DA7218_PLL_CTRL);
+		if ((pll_ctrl & DA7218_PLL_MODE_MASK) != DA7218_PLL_MODE_SRM)
+			return 0;
+
+		/* Check SRM has locked */
+		i = 0;
+		success = false;
+		do {
+			pll_status = snd_soc_read(codec, DA7218_PLL_STATUS);
+			if (pll_status & DA7218_PLL_SRM_STATUS_SRM_LOCK) {
+				success = true;
+			} else {
+				++i;
+				msleep(DA7218_SRM_CHECK_DELAY);
+			}
+		} while ((i < DA7218_SRM_CHECK_TRIES) & (!success));
+
+		if (!success)
+			dev_warn(codec->dev, "SRM failed to lock\n");
+
+		return 0;
+	case SND_SOC_DAPM_POST_PMD:
+		/* PC free-running */
+		snd_soc_write(codec, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK);
+
+		if (da7218->master)
+			/* Disable DAI clks for master mode */
+			snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+					    DA7218_DAI_CLK_EN_MASK, 0);
+
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int da7218_cp_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 da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+	/*
+	 * If this is DA7217 and we're using single supply for differential
+	 * output, we really don't want to touch the charge pump.
+	 */
+	if (da7218->hp_single_supply)
+		return 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, DA7218_CP_CTRL, DA7218_CP_EN_MASK,
+				    DA7218_CP_EN_MASK);
+		return 0;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, DA7218_CP_CTRL, DA7218_CP_EN_MASK,
+				    0);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int da7218_hp_pga_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:
+		/* Enable headphone output */
+		snd_soc_update_bits(codec, w->reg, DA7218_HP_AMP_OE_MASK,
+				    DA7218_HP_AMP_OE_MASK);
+		return 0;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Headphone output high impedance */
+		snd_soc_update_bits(codec, w->reg, DA7218_HP_AMP_OE_MASK, 0);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+
+/*
+ * DAPM Widgets
+ */
+
+static const struct snd_soc_dapm_widget da7218_dapm_widgets[] = {
+	/* Input Supplies */
+	SND_SOC_DAPM_SUPPLY("Mic Bias1", DA7218_MICBIAS_EN,
+			    DA7218_MICBIAS_1_EN_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Bias2", DA7218_MICBIAS_EN,
+			    DA7218_MICBIAS_2_EN_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMic1 Left", DA7218_DMIC_1_CTRL,
+			    DA7218_DMIC_1L_EN_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMic1 Right", DA7218_DMIC_1_CTRL,
+			    DA7218_DMIC_1R_EN_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMic2 Left", DA7218_DMIC_2_CTRL,
+			    DA7218_DMIC_2L_EN_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMic2 Right", DA7218_DMIC_2_CTRL,
+			    DA7218_DMIC_2R_EN_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("DMIC1L"),
+	SND_SOC_DAPM_INPUT("DMIC1R"),
+	SND_SOC_DAPM_INPUT("DMIC2L"),
+	SND_SOC_DAPM_INPUT("DMIC2R"),
+
+	/* Input Mixer Supplies */
+	SND_SOC_DAPM_SUPPLY("Mixin1 Supply", DA7218_MIXIN_1_CTRL,
+			    DA7218_MIXIN_1_MIX_SEL_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mixin2 Supply", DA7218_MIXIN_2_CTRL,
+			    DA7218_MIXIN_2_MIX_SEL_SHIFT, DA7218_NO_INVERT,
+			    NULL, 0),
+
+	/* Input PGAs */
+	SND_SOC_DAPM_PGA("Mic1 PGA", DA7218_MIC_1_CTRL,
+			 DA7218_MIC_1_AMP_EN_SHIFT, DA7218_NO_INVERT,
+			 NULL, 0),
+	SND_SOC_DAPM_PGA("Mic2 PGA", DA7218_MIC_2_CTRL,
+			 DA7218_MIC_2_AMP_EN_SHIFT, DA7218_NO_INVERT,
+			 NULL, 0),
+	SND_SOC_DAPM_PGA("Mixin1 PGA", DA7218_MIXIN_1_CTRL,
+			 DA7218_MIXIN_1_AMP_EN_SHIFT, DA7218_NO_INVERT,
+			 NULL, 0),
+	SND_SOC_DAPM_PGA("Mixin2 PGA", DA7218_MIXIN_2_CTRL,
+			 DA7218_MIXIN_2_AMP_EN_SHIFT, DA7218_NO_INVERT,
+			 NULL, 0),
+
+	/* Mic/DMic Muxes */
+	SND_SOC_DAPM_MUX("Mic1 Mux", SND_SOC_NOPM, 0, 0, &da7218_mic1_sel_mux),
+	SND_SOC_DAPM_MUX("Mic2 Mux", SND_SOC_NOPM, 0, 0, &da7218_mic2_sel_mux),
+
+	/* Input Filters */
+	SND_SOC_DAPM_ADC_E("In Filter1L", NULL, DA7218_IN_1L_FILTER_CTRL,
+			   DA7218_IN_1L_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+			   da7218_in_filter_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_ADC_E("In Filter1R", NULL, DA7218_IN_1R_FILTER_CTRL,
+			   DA7218_IN_1R_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+			   da7218_in_filter_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_ADC_E("In Filter2L", NULL, DA7218_IN_2L_FILTER_CTRL,
+			   DA7218_IN_2L_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+			   da7218_in_filter_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_ADC_E("In Filter2R", NULL, DA7218_IN_2R_FILTER_CTRL,
+			   DA7218_IN_2R_FILTER_EN_SHIFT, DA7218_NO_INVERT,
+			   da7218_in_filter_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	/* Tone Generator */
+	SND_SOC_DAPM_SIGGEN("TONE"),
+	SND_SOC_DAPM_PGA("Tone Generator", DA7218_TONE_GEN_CFG1,
+			 DA7218_START_STOPN_SHIFT, DA7218_NO_INVERT, NULL, 0),
+
+	/* Sidetone Input */
+	SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0,
+			 &da7218_sidetone_in_sel_mux),
+	SND_SOC_DAPM_ADC("Sidetone Filter", NULL, DA7218_SIDETONE_CTRL,
+			 DA7218_SIDETONE_FILTER_EN_SHIFT, DA7218_NO_INVERT),
+
+	/* Input Mixers */
+	SND_SOC_DAPM_MIXER("Mixer DAI1L", SND_SOC_NOPM, 0, 0,
+			   da7218_out_dai1l_mix_controls,
+			   ARRAY_SIZE(da7218_out_dai1l_mix_controls)),
+	SND_SOC_DAPM_MIXER("Mixer DAI1R", SND_SOC_NOPM, 0, 0,
+			   da7218_out_dai1r_mix_controls,
+			   ARRAY_SIZE(da7218_out_dai1r_mix_controls)),
+	SND_SOC_DAPM_MIXER("Mixer DAI2L", SND_SOC_NOPM, 0, 0,
+			   da7218_out_dai2l_mix_controls,
+			   ARRAY_SIZE(da7218_out_dai2l_mix_controls)),
+	SND_SOC_DAPM_MIXER("Mixer DAI2R", SND_SOC_NOPM, 0, 0,
+			   da7218_out_dai2r_mix_controls,
+			   ARRAY_SIZE(da7218_out_dai2r_mix_controls)),
+
+	/* DAI Supply */
+	SND_SOC_DAPM_SUPPLY("DAI", DA7218_DAI_CTRL, DA7218_DAI_EN_SHIFT,
+			    DA7218_NO_INVERT, da7218_dai_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* DAI */
+	SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Output Mixers */
+	SND_SOC_DAPM_MIXER("Mixer Out FilterL", SND_SOC_NOPM, 0, 0,
+			   da7218_out_filtl_mix_controls,
+			   ARRAY_SIZE(da7218_out_filtl_mix_controls)),
+	SND_SOC_DAPM_MIXER("Mixer Out FilterR", SND_SOC_NOPM, 0, 0,
+			   da7218_out_filtr_mix_controls,
+			   ARRAY_SIZE(da7218_out_filtr_mix_controls)),
+
+	/* BiQuad Filters */
+	SND_SOC_DAPM_MUX("Out FilterL BiQuad Mux", SND_SOC_NOPM, 0, 0,
+			 &da7218_out_filtl_biq_sel_mux),
+	SND_SOC_DAPM_MUX("Out FilterR BiQuad Mux", SND_SOC_NOPM, 0, 0,
+			 &da7218_out_filtr_biq_sel_mux),
+	SND_SOC_DAPM_DAC("BiQuad Filter", NULL, DA7218_OUT_1_BIQ_5STAGE_CTRL,
+			 DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_SHIFT,
+			 DA7218_NO_INVERT),
+
+	/* Sidetone Mixers */
+	SND_SOC_DAPM_MIXER("ST Mixer Out FilterL", SND_SOC_NOPM, 0, 0,
+			   da7218_st_out_filtl_mix_controls,
+			   ARRAY_SIZE(da7218_st_out_filtl_mix_controls)),
+	SND_SOC_DAPM_MIXER("ST Mixer Out FilterR", SND_SOC_NOPM, 0, 0,
+			   da7218_st_out_filtr_mix_controls,
+			   ARRAY_SIZE(da7218_st_out_filtr_mix_controls)),
+
+	/* Output Filters */
+	SND_SOC_DAPM_DAC("Out FilterL", NULL, DA7218_OUT_1L_FILTER_CTRL,
+			 DA7218_OUT_1L_FILTER_EN_SHIFT, DA7218_NO_INVERT),
+	SND_SOC_DAPM_DAC("Out FilterR", NULL, DA7218_OUT_1R_FILTER_CTRL,
+			 DA7218_IN_1R_FILTER_EN_SHIFT, DA7218_NO_INVERT),
+
+	/* Output PGAs */
+	SND_SOC_DAPM_PGA("Mixout Left PGA", DA7218_MIXOUT_L_CTRL,
+			 DA7218_MIXOUT_L_AMP_EN_SHIFT, DA7218_NO_INVERT,
+			 NULL, 0),
+	SND_SOC_DAPM_PGA("Mixout Right PGA", DA7218_MIXOUT_R_CTRL,
+			 DA7218_MIXOUT_R_AMP_EN_SHIFT, DA7218_NO_INVERT,
+			 NULL, 0),
+	SND_SOC_DAPM_PGA_E("Headphone Left PGA", DA7218_HP_L_CTRL,
+			   DA7218_HP_L_AMP_EN_SHIFT, DA7218_NO_INVERT, NULL, 0,
+			   da7218_hp_pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_PGA_E("Headphone Right PGA", DA7218_HP_R_CTRL,
+			   DA7218_HP_R_AMP_EN_SHIFT, DA7218_NO_INVERT, NULL, 0,
+			   da7218_hp_pga_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	/* Output Supplies */
+	SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0, da7218_cp_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+
+/*
+ * DAPM Mixer Routes
+ */
+
+#define DA7218_DMIX_ROUTES(name)				\
+	{name, "In Filter1L Switch", "In Filter1L"},		\
+	{name, "In Filter1R Switch", "In Filter1R"},		\
+	{name, "In Filter2L Switch", "In Filter2L"},		\
+	{name, "In Filter2R Switch", "In Filter2R"},		\
+	{name, "ToneGen Switch", "Tone Generator"},		\
+	{name, "DAIL Switch", "DAIIN"},				\
+	{name, "DAIR Switch", "DAIIN"}
+
+#define DA7218_DMIX_ST_ROUTES(name)				\
+	{name, "Out FilterL Switch", "Out FilterL BiQuad Mux"},	\
+	{name, "Out FilterR Switch", "Out FilterR BiQuad Mux"},	\
+	{name, "Sidetone Switch", "Sidetone Filter"}
+
+
+/*
+ * DAPM audio route definition
+ */
+
+static const struct snd_soc_dapm_route da7218_audio_map[] = {
+	/* Input paths */
+	{"MIC1", NULL, "Mic Bias1"},
+	{"MIC2", NULL, "Mic Bias2"},
+	{"DMIC1L", NULL, "Mic Bias1"},
+	{"DMIC1L", NULL, "DMic1 Left"},
+	{"DMIC1R", NULL, "Mic Bias1"},
+	{"DMIC1R", NULL, "DMic1 Right"},
+	{"DMIC2L", NULL, "Mic Bias2"},
+	{"DMIC2L", NULL, "DMic2 Left"},
+	{"DMIC2R", NULL, "Mic Bias2"},
+	{"DMIC2R", NULL, "DMic2 Right"},
+
+	{"Mic1 PGA", NULL, "MIC1"},
+	{"Mic2 PGA", NULL, "MIC2"},
+
+	{"Mixin1 PGA", NULL, "Mixin1 Supply"},
+	{"Mixin2 PGA", NULL, "Mixin2 Supply"},
+
+	{"Mixin1 PGA", NULL, "Mic1 PGA"},
+	{"Mixin2 PGA", NULL, "Mic2 PGA"},
+
+	{"Mic1 Mux", "Analog", "Mixin1 PGA"},
+	{"Mic1 Mux", "Digital", "DMIC1L"},
+	{"Mic1 Mux", "Digital", "DMIC1R"},
+	{"Mic2 Mux", "Analog", "Mixin2 PGA"},
+	{"Mic2 Mux", "Digital", "DMIC2L"},
+	{"Mic2 Mux", "Digital", "DMIC2R"},
+
+	{"In Filter1L", NULL, "Mic1 Mux"},
+	{"In Filter1R", NULL, "Mic1 Mux"},
+	{"In Filter2L", NULL, "Mic2 Mux"},
+	{"In Filter2R", NULL, "Mic2 Mux"},
+
+	{"Tone Generator", NULL, "TONE"},
+
+	{"Sidetone Mux", "In Filter1L", "In Filter1L"},
+	{"Sidetone Mux", "In Filter1R", "In Filter1R"},
+	{"Sidetone Mux", "In Filter2L", "In Filter2L"},
+	{"Sidetone Mux", "In Filter2R", "In Filter2R"},
+	{"Sidetone Filter", NULL, "Sidetone Mux"},
+
+	DA7218_DMIX_ROUTES("Mixer DAI1L"),
+	DA7218_DMIX_ROUTES("Mixer DAI1R"),
+	DA7218_DMIX_ROUTES("Mixer DAI2L"),
+	DA7218_DMIX_ROUTES("Mixer DAI2R"),
+
+	{"DAIOUT", NULL, "Mixer DAI1L"},
+	{"DAIOUT", NULL, "Mixer DAI1R"},
+	{"DAIOUT", NULL, "Mixer DAI2L"},
+	{"DAIOUT", NULL, "Mixer DAI2R"},
+
+	{"DAIOUT", NULL, "DAI"},
+
+	/* Output paths */
+	{"DAIIN", NULL, "DAI"},
+
+	DA7218_DMIX_ROUTES("Mixer Out FilterL"),
+	DA7218_DMIX_ROUTES("Mixer Out FilterR"),
+
+	{"BiQuad Filter", NULL, "Mixer Out FilterL"},
+	{"BiQuad Filter", NULL, "Mixer Out FilterR"},
+
+	{"Out FilterL BiQuad Mux", "Bypass", "Mixer Out FilterL"},
+	{"Out FilterL BiQuad Mux", "Enabled", "BiQuad Filter"},
+	{"Out FilterR BiQuad Mux", "Bypass", "Mixer Out FilterR"},
+	{"Out FilterR BiQuad Mux", "Enabled", "BiQuad Filter"},
+
+	DA7218_DMIX_ST_ROUTES("ST Mixer Out FilterL"),
+	DA7218_DMIX_ST_ROUTES("ST Mixer Out FilterR"),
+
+	{"Out FilterL", NULL, "ST Mixer Out FilterL"},
+	{"Out FilterR", NULL, "ST Mixer Out FilterR"},
+
+	{"Mixout Left PGA", NULL, "Out FilterL"},
+	{"Mixout Right PGA", NULL, "Out FilterR"},
+
+	{"Headphone Left PGA", NULL, "Mixout Left PGA"},
+	{"Headphone Right PGA", NULL, "Mixout Right PGA"},
+
+	{"HPL", NULL, "Headphone Left PGA"},
+	{"HPR", NULL, "Headphone Right PGA"},
+
+	{"HPL", NULL, "Charge Pump"},
+	{"HPR", NULL, "Charge Pump"},
+};
+
+
+/*
+ * DAI operations
+ */
+
+static int da7218_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	if (da7218->mclk_rate == freq)
+		return 0;
+
+	if (((freq < 2000000) && (freq != 32768)) || (freq > 54000000)) {
+		dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
+			freq);
+		return -EINVAL;
+	}
+
+	switch (clk_id) {
+	case DA7218_CLKSRC_MCLK_SQR:
+		snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+				    DA7218_PLL_MCLK_SQR_EN_MASK,
+				    DA7218_PLL_MCLK_SQR_EN_MASK);
+		break;
+	case DA7218_CLKSRC_MCLK:
+		snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+				    DA7218_PLL_MCLK_SQR_EN_MASK, 0);
+		break;
+	default:
+		dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	if (da7218->mclk) {
+		freq = clk_round_rate(da7218->mclk, freq);
+		ret = clk_set_rate(da7218->mclk, freq);
+		if (ret) {
+			dev_err(codec_dai->dev, "Failed to set clock rate %d\n",
+				freq);
+			return ret;
+		}
+	}
+
+	da7218->mclk_rate = freq;
+
+	return 0;
+}
+
+static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+			      int source, unsigned int fref, unsigned int fout)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+	u8 pll_ctrl, indiv_bits, indiv;
+	u8 pll_frac_top, pll_frac_bot, pll_integer;
+	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_2_5_MHZ;
+		indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL;
+	} else if (da7218->mclk_rate < 2000000) {
+		dev_err(codec->dev, "PLL input clock %d below valid range\n",
+			da7218->mclk_rate);
+		return -EINVAL;
+	} else if (da7218->mclk_rate <= 5000000) {
+		indiv_bits = DA7218_PLL_INDIV_2_5_MHZ;
+		indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL;
+	} else if (da7218->mclk_rate <= 10000000) {
+		indiv_bits = DA7218_PLL_INDIV_5_10_MHZ;
+		indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL;
+	} else if (da7218->mclk_rate <= 20000000) {
+		indiv_bits = DA7218_PLL_INDIV_10_20_MHZ;
+		indiv = DA7218_PLL_INDIV_10_20_MHZ_VAL;
+	} else if (da7218->mclk_rate <= 40000000) {
+		indiv_bits = DA7218_PLL_INDIV_20_40_MHZ;
+		indiv = DA7218_PLL_INDIV_20_40_MHZ_VAL;
+	} else if (da7218->mclk_rate <= 54000000) {
+		indiv_bits = DA7218_PLL_INDIV_40_54_MHZ;
+		indiv = DA7218_PLL_INDIV_40_54_MHZ_VAL;
+	} else {
+		dev_err(codec->dev, "PLL input clock %d above valid range\n",
+			da7218->mclk_rate);
+		return -EINVAL;
+	}
+	freq_ref = (da7218->mclk_rate / indiv);
+	pll_ctrl = indiv_bits;
+
+	/* Configure PLL */
+	switch (source) {
+	case DA7218_SYSCLK_MCLK:
+		pll_ctrl |= DA7218_PLL_MODE_BYPASS;
+		snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+				    DA7218_PLL_INDIV_MASK |
+				    DA7218_PLL_MODE_MASK, pll_ctrl);
+		return 0;
+	case DA7218_SYSCLK_PLL:
+		pll_ctrl |= DA7218_PLL_MODE_NORMAL;
+		break;
+	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;
+	}
+
+	/* Calculate dividers for PLL */
+	pll_integer = fout / freq_ref;
+	frac_div = (u64)(fout % freq_ref) * 8192ULL;
+	do_div(frac_div, freq_ref);
+	pll_frac_top = (frac_div >> DA7218_BYTE_SHIFT) & DA7218_BYTE_MASK;
+	pll_frac_bot = (frac_div) & DA7218_BYTE_MASK;
+
+	/* Write PLL config & dividers */
+	snd_soc_write(codec, DA7218_PLL_FRAC_TOP, pll_frac_top);
+	snd_soc_write(codec, DA7218_PLL_FRAC_BOT, pll_frac_bot);
+	snd_soc_write(codec, DA7218_PLL_INTEGER, pll_integer);
+	snd_soc_update_bits(codec, DA7218_PLL_CTRL,
+			    DA7218_PLL_MODE_MASK | DA7218_PLL_INDIV_MASK,
+			    pll_ctrl);
+
+	return 0;
+}
+
+static int da7218_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	u8 dai_clk_mode = 0, dai_ctrl = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		da7218->master = true;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		da7218->master = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_RIGHT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			dai_clk_mode |= DA7218_DAI_WCLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			dai_clk_mode |= DA7218_DAI_CLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			dai_clk_mode |= DA7218_DAI_WCLK_POL_INV |
+					DA7218_DAI_CLK_POL_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			dai_clk_mode |= DA7218_DAI_CLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			dai_clk_mode |= DA7218_DAI_WCLK_POL_INV |
+					DA7218_DAI_CLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			dai_clk_mode |= DA7218_DAI_WCLK_POL_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		dai_ctrl |= DA7218_DAI_FORMAT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		dai_ctrl |= DA7218_DAI_FORMAT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		dai_ctrl |= DA7218_DAI_FORMAT_RIGHT_J;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		dai_ctrl |= DA7218_DAI_FORMAT_DSP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* By default 64 BCLKs per WCLK is supported */
+	dai_clk_mode |= DA7218_DAI_BCLKS_PER_WCLK_64;
+
+	snd_soc_write(codec, DA7218_DAI_CLK_MODE, dai_clk_mode);
+	snd_soc_update_bits(codec, DA7218_DAI_CTRL, DA7218_DAI_FORMAT_MASK,
+			    dai_ctrl);
+
+	return 0;
+}
+
+static int da7218_set_dai_tdm_slot(struct snd_soc_dai *dai,
+				   unsigned int tx_mask, unsigned int rx_mask,
+				   int slots, int slot_width)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	u8 dai_bclks_per_wclk;
+	u32 frame_size;
+
+	/* No channels enabled so disable TDM, revert to 64-bit frames */
+	if (!tx_mask) {
+		snd_soc_update_bits(codec, DA7218_DAI_TDM_CTRL,
+				    DA7218_DAI_TDM_CH_EN_MASK |
+				    DA7218_DAI_TDM_MODE_EN_MASK, 0);
+		snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+				    DA7218_DAI_BCLKS_PER_WCLK_MASK,
+				    DA7218_DAI_BCLKS_PER_WCLK_64);
+		return 0;
+	}
+
+	/* Check we have valid slots */
+	if (fls(tx_mask) > DA7218_DAI_TDM_MAX_SLOTS) {
+		dev_err(codec->dev, "Invalid number of slots, max = %d\n",
+			DA7218_DAI_TDM_MAX_SLOTS);
+		return -EINVAL;
+	}
+
+	/* Check we have a valid offset given (first 2 bytes of rx_mask) */
+	if (rx_mask >> DA7218_2BYTE_SHIFT) {
+		dev_err(codec->dev, "Invalid slot offset, max = %d\n",
+			DA7218_2BYTE_MASK);
+		return -EINVAL;
+	}
+
+	/* Calculate & validate frame size based on slot info provided. */
+	frame_size = slots * slot_width;
+	switch (frame_size) {
+	case 32:
+		dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_32;
+		break;
+	case 64:
+		dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_64;
+		break;
+	case 128:
+		dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_128;
+		break;
+	case 256:
+		dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_256;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid frame size\n");
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE,
+			    DA7218_DAI_BCLKS_PER_WCLK_MASK,
+			    dai_bclks_per_wclk);
+	snd_soc_write(codec, DA7218_DAI_OFFSET_LOWER,
+		      (rx_mask & DA7218_BYTE_MASK));
+	snd_soc_write(codec, DA7218_DAI_OFFSET_UPPER,
+		      ((rx_mask >> DA7218_BYTE_SHIFT) & DA7218_BYTE_MASK));
+	snd_soc_update_bits(codec, DA7218_DAI_TDM_CTRL,
+			    DA7218_DAI_TDM_CH_EN_MASK |
+			    DA7218_DAI_TDM_MODE_EN_MASK,
+			    (tx_mask << DA7218_DAI_TDM_CH_EN_SHIFT) |
+			    DA7218_DAI_TDM_MODE_EN_MASK);
+
+	return 0;
+}
+
+static int da7218_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;
+	u8 dai_ctrl = 0, fs;
+	unsigned int channels;
+
+	switch (params_width(params)) {
+	case 16:
+		dai_ctrl |= DA7218_DAI_WORD_LENGTH_S16_LE;
+		break;
+	case 20:
+		dai_ctrl |= DA7218_DAI_WORD_LENGTH_S20_LE;
+		break;
+	case 24:
+		dai_ctrl |= DA7218_DAI_WORD_LENGTH_S24_LE;
+		break;
+	case 32:
+		dai_ctrl |= DA7218_DAI_WORD_LENGTH_S32_LE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	channels = params_channels(params);
+	if ((channels < 1) || (channels > DA7218_DAI_CH_NUM_MAX)) {
+		dev_err(codec->dev,
+			"Invalid number of channels, only 1 to %d supported\n",
+			DA7218_DAI_CH_NUM_MAX);
+		return -EINVAL;
+	}
+	dai_ctrl |= channels << DA7218_DAI_CH_NUM_SHIFT;
+
+	switch (params_rate(params)) {
+	case 8000:
+		fs = DA7218_SR_8000;
+		break;
+	case 11025:
+		fs = DA7218_SR_11025;
+		break;
+	case 12000:
+		fs = DA7218_SR_12000;
+		break;
+	case 16000:
+		fs = DA7218_SR_16000;
+		break;
+	case 22050:
+		fs = DA7218_SR_22050;
+		break;
+	case 24000:
+		fs = DA7218_SR_24000;
+		break;
+	case 32000:
+		fs = DA7218_SR_32000;
+		break;
+	case 44100:
+		fs = DA7218_SR_44100;
+		break;
+	case 48000:
+		fs = DA7218_SR_48000;
+		break;
+	case 88200:
+		fs = DA7218_SR_88200;
+		break;
+	case 96000:
+		fs = DA7218_SR_96000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, DA7218_DAI_CTRL,
+			    DA7218_DAI_WORD_LENGTH_MASK | DA7218_DAI_CH_NUM_MASK,
+			    dai_ctrl);
+	/* SRs tied for ADCs and DACs. */
+	snd_soc_write(codec, DA7218_SR,
+		      (fs << DA7218_SR_DAC_SHIFT) | (fs << DA7218_SR_ADC_SHIFT));
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops da7218_dai_ops = {
+	.hw_params	= da7218_hw_params,
+	.set_sysclk	= da7218_set_dai_sysclk,
+	.set_pll	= da7218_set_dai_pll,
+	.set_fmt	= da7218_set_dai_fmt,
+	.set_tdm_slot	= da7218_set_dai_tdm_slot,
+};
+
+#define DA7218_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver da7218_dai = {
+	.name = "da7218-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 4,	/* Only 2 channels of data */
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = DA7218_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 4,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = DA7218_FORMATS,
+	},
+	.ops = &da7218_dai_ops,
+	.symmetric_rates = 1,
+	.symmetric_channels = 1,
+	.symmetric_samplebits = 1,
+};
+
+
+/*
+ * HP Detect
+ */
+
+int da7218_hpldet(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+{
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+	if (da7218->dev_id == DA7217_DEV_ID)
+		return -EINVAL;
+
+	da7218->jack = jack;
+	snd_soc_update_bits(codec, DA7218_HPLDET_JACK,
+			    DA7218_HPLDET_JACK_EN_MASK,
+			    jack ? DA7218_HPLDET_JACK_EN_MASK : 0);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(da7218_hpldet);
+
+static void da7218_micldet_irq(struct snd_soc_codec *codec)
+{
+	char *envp[] = {
+		"EVENT=MIC_LEVEL_DETECT",
+		NULL,
+	};
+
+	kobject_uevent_env(&codec->dev->kobj, KOBJ_CHANGE, envp);
+}
+
+static void da7218_hpldet_irq(struct snd_soc_codec *codec)
+{
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	u8 jack_status;
+	int report;
+
+	jack_status = snd_soc_read(codec, DA7218_EVENT_STATUS);
+
+	if (jack_status & DA7218_HPLDET_JACK_STS_MASK)
+		report = SND_JACK_HEADPHONE;
+	else
+		report = 0;
+
+	snd_soc_jack_report(da7218->jack, report, SND_JACK_HEADPHONE);
+}
+
+/*
+ * IRQ
+ */
+
+static irqreturn_t da7218_irq_thread(int irq, void *data)
+{
+	struct snd_soc_codec *codec = data;
+	u8 status;
+
+	/* Read IRQ status reg */
+	status = snd_soc_read(codec, DA7218_EVENT);
+	if (!status)
+		return IRQ_NONE;
+
+	/* Mic level detect */
+	if (status & DA7218_LVL_DET_EVENT_MASK)
+		da7218_micldet_irq(codec);
+
+	/* HP detect */
+	if (status & DA7218_HPLDET_JACK_EVENT_MASK)
+		da7218_hpldet_irq(codec);
+
+	/* Clear interrupts */
+	snd_soc_write(codec, DA7218_EVENT, status);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * DT
+ */
+
+static const struct of_device_id da7218_of_match[] = {
+	{ .compatible = "dlg,da7217", .data = (void *) DA7217_DEV_ID },
+	{ .compatible = "dlg,da7218", .data = (void *) DA7218_DEV_ID },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, da7218_of_match);
+
+static inline int da7218_of_get_id(struct device *dev)
+{
+	const struct of_device_id *id = of_match_device(da7218_of_match, dev);
+
+	if (id)
+		return (uintptr_t)id->data;
+	else
+		return -EINVAL;
+}
+
+static enum da7218_micbias_voltage
+	da7218_of_micbias_lvl(struct snd_soc_codec *codec, u32 val)
+{
+	switch (val) {
+	case 1200:
+		return DA7218_MICBIAS_1_2V;
+	case 1600:
+		return DA7218_MICBIAS_1_6V;
+	case 1800:
+		return DA7218_MICBIAS_1_8V;
+	case 2000:
+		return DA7218_MICBIAS_2_0V;
+	case 2200:
+		return DA7218_MICBIAS_2_2V;
+	case 2400:
+		return DA7218_MICBIAS_2_4V;
+	case 2600:
+		return DA7218_MICBIAS_2_6V;
+	case 2800:
+		return DA7218_MICBIAS_2_8V;
+	case 3000:
+		return DA7218_MICBIAS_3_0V;
+	default:
+		dev_warn(codec->dev, "Invalid micbias level");
+		return DA7218_MICBIAS_1_6V;
+	}
+}
+
+static enum da7218_mic_amp_in_sel
+	da7218_of_mic_amp_in_sel(struct snd_soc_codec *codec, const char *str)
+{
+	if (!strcmp(str, "diff")) {
+		return DA7218_MIC_AMP_IN_SEL_DIFF;
+	} else if (!strcmp(str, "se_p")) {
+		return DA7218_MIC_AMP_IN_SEL_SE_P;
+	} else if (!strcmp(str, "se_n")) {
+		return DA7218_MIC_AMP_IN_SEL_SE_N;
+	} else {
+		dev_warn(codec->dev, "Invalid mic input type selection");
+		return DA7218_MIC_AMP_IN_SEL_DIFF;
+	}
+}
+
+static enum da7218_dmic_data_sel
+	da7218_of_dmic_data_sel(struct snd_soc_codec *codec, const char *str)
+{
+	if (!strcmp(str, "lrise_rfall")) {
+		return DA7218_DMIC_DATA_LRISE_RFALL;
+	} else if (!strcmp(str, "lfall_rrise")) {
+		return DA7218_DMIC_DATA_LFALL_RRISE;
+	} else {
+		dev_warn(codec->dev, "Invalid DMIC data type selection");
+		return DA7218_DMIC_DATA_LRISE_RFALL;
+	}
+}
+
+static enum da7218_dmic_samplephase
+	da7218_of_dmic_samplephase(struct snd_soc_codec *codec, const char *str)
+{
+	if (!strcmp(str, "on_clkedge")) {
+		return DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+	} else if (!strcmp(str, "between_clkedge")) {
+		return DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE;
+	} else {
+		dev_warn(codec->dev, "Invalid DMIC sample phase");
+		return DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+	}
+}
+
+static enum da7218_dmic_clk_rate
+	da7218_of_dmic_clkrate(struct snd_soc_codec *codec, u32 val)
+{
+	switch (val) {
+	case 1500000:
+		return DA7218_DMIC_CLK_1_5MHZ;
+	case 3000000:
+		return DA7218_DMIC_CLK_3_0MHZ;
+	default:
+		dev_warn(codec->dev, "Invalid DMIC clock rate");
+		return DA7218_DMIC_CLK_3_0MHZ;
+	}
+}
+
+static enum da7218_hpldet_jack_rate
+	da7218_of_jack_rate(struct snd_soc_codec *codec, u32 val)
+{
+	switch (val) {
+	case 5:
+		return DA7218_HPLDET_JACK_RATE_5US;
+	case 10:
+		return DA7218_HPLDET_JACK_RATE_10US;
+	case 20:
+		return DA7218_HPLDET_JACK_RATE_20US;
+	case 40:
+		return DA7218_HPLDET_JACK_RATE_40US;
+	case 80:
+		return DA7218_HPLDET_JACK_RATE_80US;
+	case 160:
+		return DA7218_HPLDET_JACK_RATE_160US;
+	case 320:
+		return DA7218_HPLDET_JACK_RATE_320US;
+	case 640:
+		return DA7218_HPLDET_JACK_RATE_640US;
+	default:
+		dev_warn(codec->dev, "Invalid jack detect rate");
+		return DA7218_HPLDET_JACK_RATE_40US;
+	}
+}
+
+static enum da7218_hpldet_jack_debounce
+	da7218_of_jack_debounce(struct snd_soc_codec *codec, u32 val)
+{
+	switch (val) {
+	case 0:
+		return DA7218_HPLDET_JACK_DEBOUNCE_OFF;
+	case 2:
+		return DA7218_HPLDET_JACK_DEBOUNCE_2;
+	case 3:
+		return DA7218_HPLDET_JACK_DEBOUNCE_3;
+	case 4:
+		return DA7218_HPLDET_JACK_DEBOUNCE_4;
+	default:
+		dev_warn(codec->dev, "Invalid jack debounce");
+		return DA7218_HPLDET_JACK_DEBOUNCE_2;
+	}
+}
+
+static enum da7218_hpldet_jack_thr
+	da7218_of_jack_thr(struct snd_soc_codec *codec, u32 val)
+{
+	switch (val) {
+	case 84:
+		return DA7218_HPLDET_JACK_THR_84PCT;
+	case 88:
+		return DA7218_HPLDET_JACK_THR_88PCT;
+	case 92:
+		return DA7218_HPLDET_JACK_THR_92PCT;
+	case 96:
+		return DA7218_HPLDET_JACK_THR_96PCT;
+	default:
+		dev_warn(codec->dev, "Invalid jack threshold level");
+		return DA7218_HPLDET_JACK_THR_84PCT;
+	}
+}
+
+static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_codec *codec)
+{
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct device_node *np = codec->dev->of_node;
+	struct device_node *hpldet_np;
+	struct da7218_pdata *pdata;
+	struct da7218_hpldet_pdata *hpldet_pdata;
+	const char *of_str;
+	u32 of_val32;
+
+	pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_warn(codec->dev, "Failed to allocate memory for pdata\n");
+		return NULL;
+	}
+
+	if (of_property_read_u32(np, "dlg,micbias1-lvl-millivolt", &of_val32) >= 0)
+		pdata->micbias1_lvl = da7218_of_micbias_lvl(codec, of_val32);
+	else
+		pdata->micbias1_lvl = DA7218_MICBIAS_1_6V;
+
+	if (of_property_read_u32(np, "dlg,micbias2-lvl-millivolt", &of_val32) >= 0)
+		pdata->micbias2_lvl = da7218_of_micbias_lvl(codec, of_val32);
+	else
+		pdata->micbias2_lvl = DA7218_MICBIAS_1_6V;
+
+	if (!of_property_read_string(np, "dlg,mic1-amp-in-sel", &of_str))
+		pdata->mic1_amp_in_sel =
+			da7218_of_mic_amp_in_sel(codec, of_str);
+	else
+		pdata->mic1_amp_in_sel = DA7218_MIC_AMP_IN_SEL_DIFF;
+
+	if (!of_property_read_string(np, "dlg,mic2-amp-in-sel", &of_str))
+		pdata->mic2_amp_in_sel =
+			da7218_of_mic_amp_in_sel(codec, of_str);
+	else
+		pdata->mic2_amp_in_sel = DA7218_MIC_AMP_IN_SEL_DIFF;
+
+	if (!of_property_read_string(np, "dlg,dmic1-data-sel", &of_str))
+		pdata->dmic1_data_sel =	da7218_of_dmic_data_sel(codec, of_str);
+	else
+		pdata->dmic1_data_sel =	DA7218_DMIC_DATA_LRISE_RFALL;
+
+	if (!of_property_read_string(np, "dlg,dmic1-samplephase", &of_str))
+		pdata->dmic1_samplephase =
+			da7218_of_dmic_samplephase(codec, of_str);
+	else
+		pdata->dmic1_samplephase = DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+
+	if (of_property_read_u32(np, "dlg,dmic1-clkrate-hz", &of_val32) >= 0)
+		pdata->dmic1_clk_rate = da7218_of_dmic_clkrate(codec, of_val32);
+	else
+		pdata->dmic1_clk_rate = DA7218_DMIC_CLK_3_0MHZ;
+
+	if (!of_property_read_string(np, "dlg,dmic2-data-sel", &of_str))
+		pdata->dmic2_data_sel = da7218_of_dmic_data_sel(codec, of_str);
+	else
+		pdata->dmic2_data_sel =	DA7218_DMIC_DATA_LRISE_RFALL;
+
+	if (!of_property_read_string(np, "dlg,dmic2-samplephase", &of_str))
+		pdata->dmic2_samplephase =
+			da7218_of_dmic_samplephase(codec, of_str);
+	else
+		pdata->dmic2_samplephase = DA7218_DMIC_SAMPLE_ON_CLKEDGE;
+
+	if (of_property_read_u32(np, "dlg,dmic2-clkrate-hz", &of_val32) >= 0)
+		pdata->dmic2_clk_rate = da7218_of_dmic_clkrate(codec, of_val32);
+	else
+		pdata->dmic2_clk_rate = DA7218_DMIC_CLK_3_0MHZ;
+
+	if (da7218->dev_id == DA7217_DEV_ID) {
+		if (of_property_read_bool(np, "dlg,hp-diff-single-supply"))
+			pdata->hp_diff_single_supply = true;
+	}
+
+	if (da7218->dev_id == DA7218_DEV_ID) {
+		hpldet_np = of_find_node_by_name(np, "da7218_hpldet");
+		if (!hpldet_np)
+			return pdata;
+
+		hpldet_pdata = devm_kzalloc(codec->dev, sizeof(*hpldet_pdata),
+					    GFP_KERNEL);
+		if (!hpldet_pdata) {
+			dev_warn(codec->dev,
+				 "Failed to allocate memory for hpldet pdata\n");
+			of_node_put(hpldet_np);
+			return pdata;
+		}
+		pdata->hpldet_pdata = hpldet_pdata;
+
+		if (of_property_read_u32(hpldet_np, "dlg,jack-rate-us",
+					 &of_val32) >= 0)
+			hpldet_pdata->jack_rate =
+				da7218_of_jack_rate(codec, of_val32);
+		else
+			hpldet_pdata->jack_rate = DA7218_HPLDET_JACK_RATE_40US;
+
+		if (of_property_read_u32(hpldet_np, "dlg,jack-debounce",
+					 &of_val32) >= 0)
+			hpldet_pdata->jack_debounce =
+				da7218_of_jack_debounce(codec, of_val32);
+		else
+			hpldet_pdata->jack_debounce =
+				DA7218_HPLDET_JACK_DEBOUNCE_2;
+
+		if (of_property_read_u32(hpldet_np, "dlg,jack-threshold-pct",
+					 &of_val32) >= 0)
+			hpldet_pdata->jack_thr =
+				da7218_of_jack_thr(codec, of_val32);
+		else
+			hpldet_pdata->jack_thr = DA7218_HPLDET_JACK_THR_84PCT;
+
+		if (of_property_read_bool(hpldet_np, "dlg,comp-inv"))
+			hpldet_pdata->comp_inv = true;
+
+		if (of_property_read_bool(hpldet_np, "dlg,hyst"))
+			hpldet_pdata->hyst = true;
+
+		if (of_property_read_bool(hpldet_np, "dlg,discharge"))
+			hpldet_pdata->discharge = true;
+
+		of_node_put(hpldet_np);
+	}
+
+	return pdata;
+}
+
+
+/*
+ * Codec driver functions
+ */
+
+static int da7218_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	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 */
+			if (da7218->mclk) {
+				ret = clk_prepare_enable(da7218->mclk);
+				if (ret) {
+					dev_err(codec->dev,
+						"Failed to enable mclk\n");
+					return ret;
+				}
+			}
+
+			/* Master bias */
+			snd_soc_update_bits(codec, DA7218_REFERENCES,
+					    DA7218_BIAS_EN_MASK,
+					    DA7218_BIAS_EN_MASK);
+
+			/* Internal LDO */
+			snd_soc_update_bits(codec, DA7218_LDO_CTRL,
+					    DA7218_LDO_EN_MASK,
+					    DA7218_LDO_EN_MASK);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* Only disable if jack detection disabled */
+		if (!da7218->jack) {
+			/* Internal LDO */
+			snd_soc_update_bits(codec, DA7218_LDO_CTRL,
+					    DA7218_LDO_EN_MASK, 0);
+
+			/* Master bias */
+			snd_soc_update_bits(codec, DA7218_REFERENCES,
+					    DA7218_BIAS_EN_MASK, 0);
+		}
+
+		/* MCLK */
+		if (da7218->mclk)
+			clk_disable_unprepare(da7218->mclk);
+		break;
+	}
+
+	return 0;
+}
+
+static const char *da7218_supply_names[DA7218_NUM_SUPPLIES] = {
+	[DA7218_SUPPLY_VDD] = "VDD",
+	[DA7218_SUPPLY_VDDMIC] = "VDDMIC",
+	[DA7218_SUPPLY_VDDIO] = "VDDIO",
+};
+
+static int da7218_handle_supplies(struct snd_soc_codec *codec)
+{
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct regulator *vddio;
+	u8 io_voltage_lvl = DA7218_IO_VOLTAGE_LEVEL_2_5V_3_6V;
+	int i, ret;
+
+	/* Get required supplies */
+	for (i = 0; i < DA7218_NUM_SUPPLIES; ++i)
+		da7218->supplies[i].supply = da7218_supply_names[i];
+
+	ret = devm_regulator_bulk_get(codec->dev, DA7218_NUM_SUPPLIES,
+				      da7218->supplies);
+	if (ret) {
+		dev_err(codec->dev, "Failed to get supplies\n");
+		return ret;
+	}
+
+	/* Determine VDDIO voltage provided */
+	vddio = da7218->supplies[DA7218_SUPPLY_VDDIO].consumer;
+	ret = regulator_get_voltage(vddio);
+	if (ret < 1500000)
+		dev_warn(codec->dev, "Invalid VDDIO voltage\n");
+	else if (ret < 2500000)
+		io_voltage_lvl = DA7218_IO_VOLTAGE_LEVEL_1_5V_2_5V;
+
+	/* Enable main supplies */
+	ret = regulator_bulk_enable(DA7218_NUM_SUPPLIES, da7218->supplies);
+	if (ret) {
+		dev_err(codec->dev, "Failed to enable supplies\n");
+		return ret;
+	}
+
+	/* Ensure device in active mode */
+	snd_soc_write(codec, DA7218_SYSTEM_ACTIVE, DA7218_SYSTEM_ACTIVE_MASK);
+
+	/* Update IO voltage level range */
+	snd_soc_write(codec, DA7218_IO_CTRL, io_voltage_lvl);
+
+	return 0;
+}
+
+static void da7218_handle_pdata(struct snd_soc_codec *codec)
+{
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	struct da7218_pdata *pdata = da7218->pdata;
+
+	if (pdata) {
+		u8 micbias_lvl = 0, dmic_cfg = 0;
+
+		/* Mic Bias voltages */
+		switch (pdata->micbias1_lvl) {
+		case DA7218_MICBIAS_1_2V:
+			micbias_lvl |= DA7218_MICBIAS_1_LP_MODE_MASK;
+			break;
+		case DA7218_MICBIAS_1_6V:
+		case DA7218_MICBIAS_1_8V:
+		case DA7218_MICBIAS_2_0V:
+		case DA7218_MICBIAS_2_2V:
+		case DA7218_MICBIAS_2_4V:
+		case DA7218_MICBIAS_2_6V:
+		case DA7218_MICBIAS_2_8V:
+		case DA7218_MICBIAS_3_0V:
+			micbias_lvl |= (pdata->micbias1_lvl <<
+					DA7218_MICBIAS_1_LEVEL_SHIFT);
+			break;
+		}
+
+		switch (pdata->micbias2_lvl) {
+		case DA7218_MICBIAS_1_2V:
+			micbias_lvl |= DA7218_MICBIAS_2_LP_MODE_MASK;
+			break;
+		case DA7218_MICBIAS_1_6V:
+		case DA7218_MICBIAS_1_8V:
+		case DA7218_MICBIAS_2_0V:
+		case DA7218_MICBIAS_2_2V:
+		case DA7218_MICBIAS_2_4V:
+		case DA7218_MICBIAS_2_6V:
+		case DA7218_MICBIAS_2_8V:
+		case DA7218_MICBIAS_3_0V:
+			micbias_lvl |= (pdata->micbias2_lvl <<
+					 DA7218_MICBIAS_2_LEVEL_SHIFT);
+			break;
+		}
+
+		snd_soc_write(codec, DA7218_MICBIAS_CTRL, micbias_lvl);
+
+		/* Mic */
+		switch (pdata->mic1_amp_in_sel) {
+		case DA7218_MIC_AMP_IN_SEL_DIFF:
+		case DA7218_MIC_AMP_IN_SEL_SE_P:
+		case DA7218_MIC_AMP_IN_SEL_SE_N:
+			snd_soc_write(codec, DA7218_MIC_1_SELECT,
+				      pdata->mic1_amp_in_sel);
+			break;
+		}
+
+		switch (pdata->mic2_amp_in_sel) {
+		case DA7218_MIC_AMP_IN_SEL_DIFF:
+		case DA7218_MIC_AMP_IN_SEL_SE_P:
+		case DA7218_MIC_AMP_IN_SEL_SE_N:
+			snd_soc_write(codec, DA7218_MIC_2_SELECT,
+				      pdata->mic2_amp_in_sel);
+			break;
+		}
+
+		/* DMic */
+		switch (pdata->dmic1_data_sel) {
+		case DA7218_DMIC_DATA_LFALL_RRISE:
+		case DA7218_DMIC_DATA_LRISE_RFALL:
+			dmic_cfg |= (pdata->dmic1_data_sel <<
+				     DA7218_DMIC_1_DATA_SEL_SHIFT);
+			break;
+		}
+
+		switch (pdata->dmic1_samplephase) {
+		case DA7218_DMIC_SAMPLE_ON_CLKEDGE:
+		case DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE:
+			dmic_cfg |= (pdata->dmic1_samplephase <<
+				     DA7218_DMIC_1_SAMPLEPHASE_SHIFT);
+			break;
+		}
+
+		switch (pdata->dmic1_clk_rate) {
+		case DA7218_DMIC_CLK_3_0MHZ:
+		case DA7218_DMIC_CLK_1_5MHZ:
+			dmic_cfg |= (pdata->dmic1_clk_rate <<
+				     DA7218_DMIC_1_CLK_RATE_SHIFT);
+			break;
+		}
+
+		snd_soc_update_bits(codec, DA7218_DMIC_1_CTRL,
+				    DA7218_DMIC_1_DATA_SEL_MASK |
+				    DA7218_DMIC_1_SAMPLEPHASE_MASK |
+				    DA7218_DMIC_1_CLK_RATE_MASK, dmic_cfg);
+
+		dmic_cfg = 0;
+		switch (pdata->dmic2_data_sel) {
+		case DA7218_DMIC_DATA_LFALL_RRISE:
+		case DA7218_DMIC_DATA_LRISE_RFALL:
+			dmic_cfg |= (pdata->dmic2_data_sel <<
+				     DA7218_DMIC_2_DATA_SEL_SHIFT);
+			break;
+		}
+
+		switch (pdata->dmic2_samplephase) {
+		case DA7218_DMIC_SAMPLE_ON_CLKEDGE:
+		case DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE:
+			dmic_cfg |= (pdata->dmic2_samplephase <<
+				     DA7218_DMIC_2_SAMPLEPHASE_SHIFT);
+			break;
+		}
+
+		switch (pdata->dmic2_clk_rate) {
+		case DA7218_DMIC_CLK_3_0MHZ:
+		case DA7218_DMIC_CLK_1_5MHZ:
+			dmic_cfg |= (pdata->dmic2_clk_rate <<
+				     DA7218_DMIC_2_CLK_RATE_SHIFT);
+			break;
+		}
+
+		snd_soc_update_bits(codec, DA7218_DMIC_2_CTRL,
+				    DA7218_DMIC_2_DATA_SEL_MASK |
+				    DA7218_DMIC_2_SAMPLEPHASE_MASK |
+				    DA7218_DMIC_2_CLK_RATE_MASK, dmic_cfg);
+
+		/* DA7217 Specific */
+		if (da7218->dev_id == DA7217_DEV_ID) {
+			da7218->hp_single_supply =
+				pdata->hp_diff_single_supply;
+
+			if (da7218->hp_single_supply) {
+				snd_soc_write(codec, DA7218_HP_DIFF_UNLOCK,
+					      DA7218_HP_DIFF_UNLOCK_VAL);
+				snd_soc_update_bits(codec, DA7218_HP_DIFF_CTRL,
+						    DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK,
+						    DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK);
+			}
+		}
+
+		/* DA7218 Specific */
+		if ((da7218->dev_id == DA7218_DEV_ID) &&
+		    (pdata->hpldet_pdata)) {
+			struct da7218_hpldet_pdata *hpldet_pdata =
+				pdata->hpldet_pdata;
+			u8 hpldet_cfg = 0;
+
+			switch (hpldet_pdata->jack_rate) {
+			case DA7218_HPLDET_JACK_RATE_5US:
+			case DA7218_HPLDET_JACK_RATE_10US:
+			case DA7218_HPLDET_JACK_RATE_20US:
+			case DA7218_HPLDET_JACK_RATE_40US:
+			case DA7218_HPLDET_JACK_RATE_80US:
+			case DA7218_HPLDET_JACK_RATE_160US:
+			case DA7218_HPLDET_JACK_RATE_320US:
+			case DA7218_HPLDET_JACK_RATE_640US:
+				hpldet_cfg |=
+					(hpldet_pdata->jack_rate <<
+					 DA7218_HPLDET_JACK_RATE_SHIFT);
+				break;
+			}
+
+			switch (hpldet_pdata->jack_debounce) {
+			case DA7218_HPLDET_JACK_DEBOUNCE_OFF:
+			case DA7218_HPLDET_JACK_DEBOUNCE_2:
+			case DA7218_HPLDET_JACK_DEBOUNCE_3:
+			case DA7218_HPLDET_JACK_DEBOUNCE_4:
+				hpldet_cfg |=
+					(hpldet_pdata->jack_debounce <<
+					 DA7218_HPLDET_JACK_DEBOUNCE_SHIFT);
+				break;
+			}
+
+			switch (hpldet_pdata->jack_thr) {
+			case DA7218_HPLDET_JACK_THR_84PCT:
+			case DA7218_HPLDET_JACK_THR_88PCT:
+			case DA7218_HPLDET_JACK_THR_92PCT:
+			case DA7218_HPLDET_JACK_THR_96PCT:
+				hpldet_cfg |=
+					(hpldet_pdata->jack_thr <<
+					 DA7218_HPLDET_JACK_THR_SHIFT);
+				break;
+			}
+			snd_soc_update_bits(codec, DA7218_HPLDET_JACK,
+					    DA7218_HPLDET_JACK_RATE_MASK |
+					    DA7218_HPLDET_JACK_DEBOUNCE_MASK |
+					    DA7218_HPLDET_JACK_THR_MASK,
+					    hpldet_cfg);
+
+			hpldet_cfg = 0;
+			if (hpldet_pdata->comp_inv)
+				hpldet_cfg |= DA7218_HPLDET_COMP_INV_MASK;
+
+			if (hpldet_pdata->hyst)
+				hpldet_cfg |= DA7218_HPLDET_HYST_EN_MASK;
+
+			if (hpldet_pdata->discharge)
+				hpldet_cfg |= DA7218_HPLDET_DISCHARGE_EN_MASK;
+
+			snd_soc_write(codec, DA7218_HPLDET_CTRL, hpldet_cfg);
+		}
+	}
+}
+
+static int da7218_probe(struct snd_soc_codec *codec)
+{
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	/* Regulator configuration */
+	ret = da7218_handle_supplies(codec);
+	if (ret)
+		return ret;
+
+	/* Handle DT/Platform data */
+	if (codec->dev->of_node)
+		da7218->pdata = da7218_of_to_pdata(codec);
+	else
+		da7218->pdata = dev_get_platdata(codec->dev);
+
+	da7218_handle_pdata(codec);
+
+	/* Check if MCLK provided, if not the clock is NULL */
+	da7218->mclk = devm_clk_get(codec->dev, "mclk");
+	if (IS_ERR(da7218->mclk)) {
+		if (PTR_ERR(da7218->mclk) != -ENOENT) {
+			ret = PTR_ERR(da7218->mclk);
+			goto err_disable_reg;
+		} else {
+			da7218->mclk = NULL;
+		}
+	}
+
+	/* Default PC to free-running */
+	snd_soc_write(codec, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK);
+
+	/*
+	 * Default Output Filter mixers to off otherwise DAPM will power
+	 * Mic to HP passthrough paths by default at startup.
+	 */
+	snd_soc_write(codec, DA7218_DROUTING_OUTFILT_1L, 0);
+	snd_soc_write(codec, DA7218_DROUTING_OUTFILT_1R, 0);
+
+	/* Default CP to normal load, power mode */
+	snd_soc_update_bits(codec, DA7218_CP_CTRL,
+			    DA7218_CP_SMALL_SWITCH_FREQ_EN_MASK, 0);
+
+	/* Default gain ramping */
+	snd_soc_update_bits(codec, DA7218_MIXIN_1_CTRL,
+			    DA7218_MIXIN_1_AMP_RAMP_EN_MASK,
+			    DA7218_MIXIN_1_AMP_RAMP_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_MIXIN_2_CTRL,
+			    DA7218_MIXIN_2_AMP_RAMP_EN_MASK,
+			    DA7218_MIXIN_2_AMP_RAMP_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_IN_1L_FILTER_CTRL,
+			    DA7218_IN_1L_RAMP_EN_MASK,
+			    DA7218_IN_1L_RAMP_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_IN_1R_FILTER_CTRL,
+			    DA7218_IN_1R_RAMP_EN_MASK,
+			    DA7218_IN_1R_RAMP_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_IN_2L_FILTER_CTRL,
+			    DA7218_IN_2L_RAMP_EN_MASK,
+			    DA7218_IN_2L_RAMP_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_IN_2R_FILTER_CTRL,
+			    DA7218_IN_2R_RAMP_EN_MASK,
+			    DA7218_IN_2R_RAMP_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_DGS_GAIN_CTRL,
+			    DA7218_DGS_RAMP_EN_MASK, DA7218_DGS_RAMP_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_OUT_1L_FILTER_CTRL,
+			    DA7218_OUT_1L_RAMP_EN_MASK,
+			    DA7218_OUT_1L_RAMP_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_OUT_1R_FILTER_CTRL,
+			    DA7218_OUT_1R_RAMP_EN_MASK,
+			    DA7218_OUT_1R_RAMP_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_HP_L_CTRL,
+			    DA7218_HP_L_AMP_RAMP_EN_MASK,
+			    DA7218_HP_L_AMP_RAMP_EN_MASK);
+	snd_soc_update_bits(codec, DA7218_HP_R_CTRL,
+			    DA7218_HP_R_AMP_RAMP_EN_MASK,
+			    DA7218_HP_R_AMP_RAMP_EN_MASK);
+
+	/* Default infinite tone gen, start/stop by Kcontrol */
+	snd_soc_write(codec, DA7218_TONE_GEN_CYCLES, DA7218_BEEP_CYCLES_MASK);
+
+	/* DA7217 specific config */
+	if (da7218->dev_id == DA7217_DEV_ID) {
+		snd_soc_update_bits(codec, DA7218_HP_DIFF_CTRL,
+				    DA7218_HP_AMP_DIFF_MODE_EN_MASK,
+				    DA7218_HP_AMP_DIFF_MODE_EN_MASK);
+
+		/* Only DA7218 supports HP detect, mask off for DA7217 */
+		snd_soc_write(codec, DA7218_EVENT_MASK,
+			      DA7218_HPLDET_JACK_EVENT_IRQ_MSK_MASK);
+	}
+
+	if (da7218->irq) {
+		ret = devm_request_threaded_irq(codec->dev, da7218->irq, NULL,
+						da7218_irq_thread,
+						IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+						"da7218", codec);
+		if (ret != 0) {
+			dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
+				da7218->irq, ret);
+			goto err_disable_reg;
+		}
+
+	}
+
+	return 0;
+
+err_disable_reg:
+	regulator_bulk_disable(DA7218_NUM_SUPPLIES, da7218->supplies);
+
+	return ret;
+}
+
+static int da7218_remove(struct snd_soc_codec *codec)
+{
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+	regulator_bulk_disable(DA7218_NUM_SUPPLIES, da7218->supplies);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int da7218_suspend(struct snd_soc_codec *codec)
+{
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+	da7218_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	/* Put device into standby mode if jack detection disabled */
+	if (!da7218->jack)
+		snd_soc_write(codec, DA7218_SYSTEM_ACTIVE, 0);
+
+	return 0;
+}
+
+static int da7218_resume(struct snd_soc_codec *codec)
+{
+	struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec);
+
+	/* Put device into active mode if previously moved to standby */
+	if (!da7218->jack)
+		snd_soc_write(codec, DA7218_SYSTEM_ACTIVE,
+			      DA7218_SYSTEM_ACTIVE_MASK);
+
+	da7218_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+}
+#else
+#define da7218_suspend NULL
+#define da7218_resume NULL
+#endif
+
+static struct snd_soc_codec_driver soc_codec_dev_da7218 = {
+	.probe			= da7218_probe,
+	.remove			= da7218_remove,
+	.suspend		= da7218_suspend,
+	.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),
+};
+
+
+/*
+ * Regmap configs
+ */
+
+static struct reg_default da7218_reg_defaults[] = {
+	{ DA7218_SYSTEM_ACTIVE, 0x00 },
+	{ DA7218_CIF_CTRL, 0x00 },
+	{ DA7218_SPARE1, 0x00 },
+	{ DA7218_SR, 0xAA },
+	{ DA7218_PC_COUNT, 0x02 },
+	{ DA7218_GAIN_RAMP_CTRL, 0x00 },
+	{ DA7218_CIF_TIMEOUT_CTRL, 0x01 },
+	{ DA7218_SYSTEM_MODES_INPUT, 0x00 },
+	{ DA7218_SYSTEM_MODES_OUTPUT, 0x00 },
+	{ DA7218_IN_1L_FILTER_CTRL, 0x00 },
+	{ DA7218_IN_1R_FILTER_CTRL, 0x00 },
+	{ DA7218_IN_2L_FILTER_CTRL, 0x00 },
+	{ DA7218_IN_2R_FILTER_CTRL, 0x00 },
+	{ DA7218_OUT_1L_FILTER_CTRL, 0x40 },
+	{ DA7218_OUT_1R_FILTER_CTRL, 0x40 },
+	{ DA7218_OUT_1_HPF_FILTER_CTRL, 0x80 },
+	{ DA7218_OUT_1_EQ_12_FILTER_CTRL, 0x77 },
+	{ DA7218_OUT_1_EQ_34_FILTER_CTRL, 0x77 },
+	{ DA7218_OUT_1_EQ_5_FILTER_CTRL, 0x07 },
+	{ DA7218_OUT_1_BIQ_5STAGE_CTRL, 0x40 },
+	{ DA7218_OUT_1_BIQ_5STAGE_DATA, 0x00 },
+	{ DA7218_OUT_1_BIQ_5STAGE_ADDR, 0x00 },
+	{ DA7218_MIXIN_1_CTRL, 0x48 },
+	{ DA7218_MIXIN_1_GAIN, 0x03 },
+	{ DA7218_MIXIN_2_CTRL, 0x48 },
+	{ DA7218_MIXIN_2_GAIN, 0x03 },
+	{ DA7218_ALC_CTRL1, 0x00 },
+	{ DA7218_ALC_CTRL2, 0x00 },
+	{ DA7218_ALC_CTRL3, 0x00 },
+	{ DA7218_ALC_NOISE, 0x3F },
+	{ DA7218_ALC_TARGET_MIN, 0x3F },
+	{ DA7218_ALC_TARGET_MAX, 0x00 },
+	{ DA7218_ALC_GAIN_LIMITS, 0xFF },
+	{ DA7218_ALC_ANA_GAIN_LIMITS, 0x71 },
+	{ DA7218_ALC_ANTICLIP_CTRL, 0x00 },
+	{ DA7218_AGS_ENABLE, 0x00 },
+	{ DA7218_AGS_TRIGGER, 0x09 },
+	{ DA7218_AGS_ATT_MAX, 0x00 },
+	{ DA7218_AGS_TIMEOUT, 0x00 },
+	{ DA7218_AGS_ANTICLIP_CTRL, 0x00 },
+	{ DA7218_ENV_TRACK_CTRL, 0x00 },
+	{ DA7218_LVL_DET_CTRL, 0x00 },
+	{ DA7218_LVL_DET_LEVEL, 0x7F },
+	{ DA7218_DGS_TRIGGER, 0x24 },
+	{ DA7218_DGS_ENABLE, 0x00 },
+	{ DA7218_DGS_RISE_FALL, 0x50 },
+	{ DA7218_DGS_SYNC_DELAY, 0xA3 },
+	{ DA7218_DGS_SYNC_DELAY2, 0x31 },
+	{ DA7218_DGS_SYNC_DELAY3, 0x11 },
+	{ DA7218_DGS_LEVELS, 0x01 },
+	{ DA7218_DGS_GAIN_CTRL, 0x74 },
+	{ DA7218_DROUTING_OUTDAI_1L, 0x01 },
+	{ DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN, 0x1C },
+	{ DA7218_DROUTING_OUTDAI_1R, 0x04 },
+	{ DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN, 0x1C },
+	{ DA7218_DROUTING_OUTFILT_1L, 0x01 },
+	{ DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN, 0x1C },
+	{ DA7218_DROUTING_OUTFILT_1R, 0x04 },
+	{ DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN, 0x1C },
+	{ DA7218_DROUTING_OUTDAI_2L, 0x04 },
+	{ DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN, 0x1C },
+	{ DA7218_DROUTING_OUTDAI_2R, 0x08 },
+	{ DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN, 0x1C },
+	{ DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN, 0x1C },
+	{ DA7218_DAI_CTRL, 0x28 },
+	{ DA7218_DAI_TDM_CTRL, 0x40 },
+	{ DA7218_DAI_OFFSET_LOWER, 0x00 },
+	{ DA7218_DAI_OFFSET_UPPER, 0x00 },
+	{ DA7218_DAI_CLK_MODE, 0x01 },
+	{ DA7218_PLL_CTRL, 0x04 },
+	{ DA7218_PLL_FRAC_TOP, 0x00 },
+	{ DA7218_PLL_FRAC_BOT, 0x00 },
+	{ DA7218_PLL_INTEGER, 0x20 },
+	{ DA7218_DAC_NG_CTRL, 0x00 },
+	{ DA7218_DAC_NG_SETUP_TIME, 0x00 },
+	{ DA7218_DAC_NG_OFF_THRESH, 0x00 },
+	{ DA7218_DAC_NG_ON_THRESH, 0x00 },
+	{ DA7218_TONE_GEN_CFG2, 0x00 },
+	{ DA7218_TONE_GEN_FREQ1_L, 0x55 },
+	{ DA7218_TONE_GEN_FREQ1_U, 0x15 },
+	{ DA7218_TONE_GEN_FREQ2_L, 0x00 },
+	{ DA7218_TONE_GEN_FREQ2_U, 0x40 },
+	{ DA7218_TONE_GEN_CYCLES, 0x00 },
+	{ DA7218_TONE_GEN_ON_PER, 0x02 },
+	{ DA7218_TONE_GEN_OFF_PER, 0x01 },
+	{ DA7218_CP_CTRL, 0x60 },
+	{ DA7218_CP_DELAY, 0x11 },
+	{ DA7218_CP_VOL_THRESHOLD1, 0x0E },
+	{ DA7218_MIC_1_CTRL, 0x40 },
+	{ DA7218_MIC_1_GAIN, 0x01 },
+	{ DA7218_MIC_1_SELECT, 0x00 },
+	{ DA7218_MIC_2_CTRL, 0x40 },
+	{ DA7218_MIC_2_GAIN, 0x01 },
+	{ DA7218_MIC_2_SELECT, 0x00 },
+	{ DA7218_IN_1_HPF_FILTER_CTRL, 0x80 },
+	{ DA7218_IN_2_HPF_FILTER_CTRL, 0x80 },
+	{ DA7218_ADC_1_CTRL, 0x07 },
+	{ DA7218_ADC_2_CTRL, 0x07 },
+	{ DA7218_MIXOUT_L_CTRL, 0x00 },
+	{ DA7218_MIXOUT_L_GAIN, 0x03 },
+	{ DA7218_MIXOUT_R_CTRL, 0x00 },
+	{ DA7218_MIXOUT_R_GAIN, 0x03 },
+	{ DA7218_HP_L_CTRL, 0x40 },
+	{ DA7218_HP_L_GAIN, 0x3B },
+	{ DA7218_HP_R_CTRL, 0x40 },
+	{ DA7218_HP_R_GAIN, 0x3B },
+	{ DA7218_HP_DIFF_CTRL, 0x00 },
+	{ DA7218_HP_DIFF_UNLOCK, 0xC3 },
+	{ DA7218_HPLDET_JACK, 0x0B },
+	{ DA7218_HPLDET_CTRL, 0x00 },
+	{ DA7218_REFERENCES, 0x08 },
+	{ DA7218_IO_CTRL, 0x00 },
+	{ DA7218_LDO_CTRL, 0x00 },
+	{ DA7218_SIDETONE_CTRL, 0x40 },
+	{ DA7218_SIDETONE_IN_SELECT, 0x00 },
+	{ DA7218_SIDETONE_GAIN, 0x1C },
+	{ DA7218_DROUTING_ST_OUTFILT_1L, 0x01 },
+	{ DA7218_DROUTING_ST_OUTFILT_1R, 0x02 },
+	{ DA7218_SIDETONE_BIQ_3STAGE_DATA, 0x00 },
+	{ DA7218_SIDETONE_BIQ_3STAGE_ADDR, 0x00 },
+	{ DA7218_EVENT_MASK, 0x00 },
+	{ DA7218_DMIC_1_CTRL, 0x00 },
+	{ DA7218_DMIC_2_CTRL, 0x00 },
+	{ DA7218_IN_1L_GAIN, 0x6F },
+	{ DA7218_IN_1R_GAIN, 0x6F },
+	{ DA7218_IN_2L_GAIN, 0x6F },
+	{ DA7218_IN_2R_GAIN, 0x6F },
+	{ DA7218_OUT_1L_GAIN, 0x6F },
+	{ DA7218_OUT_1R_GAIN, 0x6F },
+	{ DA7218_MICBIAS_CTRL, 0x00 },
+	{ DA7218_MICBIAS_EN, 0x00 },
+};
+
+static bool da7218_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case DA7218_STATUS1:
+	case DA7218_SOFT_RESET:
+	case DA7218_SYSTEM_STATUS:
+	case DA7218_CALIB_CTRL:
+	case DA7218_CALIB_OFFSET_AUTO_M_1:
+	case DA7218_CALIB_OFFSET_AUTO_U_1:
+	case DA7218_CALIB_OFFSET_AUTO_M_2:
+	case DA7218_CALIB_OFFSET_AUTO_U_2:
+	case DA7218_PLL_STATUS:
+	case DA7218_PLL_REFOSC_CAL:
+	case DA7218_TONE_GEN_CFG1:
+	case DA7218_ADC_MODE:
+	case DA7218_HP_SNGL_CTRL:
+	case DA7218_HPLDET_TEST:
+	case DA7218_EVENT_STATUS:
+	case DA7218_EVENT:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config da7218_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = DA7218_MICBIAS_EN,
+	.reg_defaults = da7218_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(da7218_reg_defaults),
+	.volatile_reg = da7218_volatile_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+
+/*
+ * I2C layer
+ */
+
+static int da7218_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct da7218_priv *da7218;
+	int ret;
+
+	da7218 = devm_kzalloc(&i2c->dev, sizeof(struct da7218_priv),
+			      GFP_KERNEL);
+	if (!da7218)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, da7218);
+
+	if (i2c->dev.of_node)
+		da7218->dev_id = da7218_of_get_id(&i2c->dev);
+	else
+		da7218->dev_id = id->driver_data;
+
+	if ((da7218->dev_id != DA7217_DEV_ID) &&
+	    (da7218->dev_id != DA7218_DEV_ID)) {
+		dev_err(&i2c->dev, "Invalid device Id\n");
+		return -EINVAL;
+	}
+
+	da7218->irq = i2c->irq;
+
+	da7218->regmap = devm_regmap_init_i2c(i2c, &da7218_regmap_config);
+	if (IS_ERR(da7218->regmap)) {
+		ret = PTR_ERR(da7218->regmap);
+		dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_register_codec(&i2c->dev,
+			&soc_codec_dev_da7218, &da7218_dai, 1);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register da7218 codec: %d\n",
+			ret);
+	}
+	return ret;
+}
+
+static int da7218_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id da7218_i2c_id[] = {
+	{ "da7217", DA7217_DEV_ID },
+	{ "da7218", DA7218_DEV_ID },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, da7218_i2c_id);
+
+static struct i2c_driver da7218_i2c_driver = {
+	.driver = {
+		.name = "da7218",
+		.of_match_table = of_match_ptr(da7218_of_match),
+	},
+	.probe		= da7218_i2c_probe,
+	.remove		= da7218_i2c_remove,
+	.id_table	= da7218_i2c_id,
+};
+
+module_i2c_driver(da7218_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC DA7218 Codec driver");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da7218.h b/sound/soc/codecs/da7218.h
new file mode 100644
index 0000000..c2c5904
--- /dev/null
+++ b/sound/soc/codecs/da7218.h
@@ -0,0 +1,1414 @@
+/*
+ * da7218.h - DA7218 ALSA SoC Codec Driver
+ *
+ * Copyright (c) 2015 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _DA7218_H
+#define _DA7218_H
+
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/da7218.h>
+
+
+/*
+ * Registers
+ */
+#define DA7218_SYSTEM_ACTIVE			0x0
+#define DA7218_CIF_CTRL				0x1
+#define DA7218_CHIP_ID1				0x4
+#define DA7218_CHIP_ID2				0x5
+#define DA7218_CHIP_REVISION			0x6
+#define DA7218_SPARE1				0x7
+#define DA7218_STATUS1				0x8
+#define DA7218_SOFT_RESET			0x9
+#define DA7218_SR				0xB
+#define DA7218_PC_COUNT				0xC
+#define DA7218_GAIN_RAMP_CTRL			0xD
+#define DA7218_CIF_TIMEOUT_CTRL			0x10
+#define DA7218_SYSTEM_MODES_INPUT		0x14
+#define DA7218_SYSTEM_MODES_OUTPUT		0x15
+#define DA7218_SYSTEM_STATUS			0x16
+#define DA7218_IN_1L_FILTER_CTRL		0x18
+#define DA7218_IN_1R_FILTER_CTRL		0x19
+#define DA7218_IN_2L_FILTER_CTRL		0x1A
+#define DA7218_IN_2R_FILTER_CTRL		0x1B
+#define DA7218_OUT_1L_FILTER_CTRL		0x20
+#define DA7218_OUT_1R_FILTER_CTRL		0x21
+#define DA7218_OUT_1_HPF_FILTER_CTRL		0x24
+#define DA7218_OUT_1_EQ_12_FILTER_CTRL		0x25
+#define DA7218_OUT_1_EQ_34_FILTER_CTRL		0x26
+#define DA7218_OUT_1_EQ_5_FILTER_CTRL		0x27
+#define DA7218_OUT_1_BIQ_5STAGE_CTRL		0x28
+#define DA7218_OUT_1_BIQ_5STAGE_DATA		0x29
+#define DA7218_OUT_1_BIQ_5STAGE_ADDR		0x2A
+#define DA7218_MIXIN_1_CTRL			0x2C
+#define DA7218_MIXIN_1_GAIN			0x2D
+#define DA7218_MIXIN_2_CTRL			0x2E
+#define DA7218_MIXIN_2_GAIN			0x2F
+#define DA7218_ALC_CTRL1			0x30
+#define DA7218_ALC_CTRL2			0x31
+#define DA7218_ALC_CTRL3			0x32
+#define DA7218_ALC_NOISE			0x33
+#define DA7218_ALC_TARGET_MIN			0x34
+#define DA7218_ALC_TARGET_MAX			0x35
+#define DA7218_ALC_GAIN_LIMITS			0x36
+#define DA7218_ALC_ANA_GAIN_LIMITS		0x37
+#define DA7218_ALC_ANTICLIP_CTRL		0x38
+#define DA7218_AGS_ENABLE			0x3C
+#define DA7218_AGS_TRIGGER			0x3D
+#define DA7218_AGS_ATT_MAX			0x3E
+#define DA7218_AGS_TIMEOUT			0x3F
+#define DA7218_AGS_ANTICLIP_CTRL		0x40
+#define DA7218_CALIB_CTRL			0x44
+#define DA7218_CALIB_OFFSET_AUTO_M_1		0x45
+#define DA7218_CALIB_OFFSET_AUTO_U_1		0x46
+#define DA7218_CALIB_OFFSET_AUTO_M_2		0x47
+#define DA7218_CALIB_OFFSET_AUTO_U_2		0x48
+#define DA7218_ENV_TRACK_CTRL			0x4C
+#define DA7218_LVL_DET_CTRL			0x50
+#define DA7218_LVL_DET_LEVEL			0x51
+#define DA7218_DGS_TRIGGER			0x54
+#define DA7218_DGS_ENABLE			0x55
+#define DA7218_DGS_RISE_FALL			0x56
+#define DA7218_DGS_SYNC_DELAY			0x57
+#define DA7218_DGS_SYNC_DELAY2			0x58
+#define DA7218_DGS_SYNC_DELAY3			0x59
+#define DA7218_DGS_LEVELS			0x5A
+#define DA7218_DGS_GAIN_CTRL			0x5B
+#define DA7218_DROUTING_OUTDAI_1L		0x5C
+#define DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN	0x5D
+#define DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN	0x5E
+#define DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN	0x5F
+#define DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN	0x60
+#define DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN	0x61
+#define DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN	0x62
+#define DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN	0x63
+#define DA7218_DROUTING_OUTDAI_1R		0x64
+#define DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN	0x65
+#define DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN	0x66
+#define DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN	0x67
+#define DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN	0x68
+#define DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN	0x69
+#define DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN	0x6A
+#define DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN	0x6B
+#define DA7218_DROUTING_OUTFILT_1L		0x6C
+#define DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN	0x6D
+#define DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN	0x6E
+#define DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN	0x6F
+#define DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN	0x70
+#define DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN	0x71
+#define DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN	0x72
+#define DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN	0x73
+#define DA7218_DROUTING_OUTFILT_1R		0x74
+#define DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN	0x75
+#define DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN	0x76
+#define DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN	0x77
+#define DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN	0x78
+#define DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN	0x79
+#define DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN	0x7A
+#define DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN	0x7B
+#define DA7218_DROUTING_OUTDAI_2L		0x7C
+#define DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN	0x7D
+#define DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN	0x7E
+#define DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN	0x7F
+#define DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN	0x80
+#define DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN	0x81
+#define DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN	0x82
+#define DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN	0x83
+#define DA7218_DROUTING_OUTDAI_2R		0x84
+#define DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN	0x85
+#define DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN	0x86
+#define DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN	0x87
+#define DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN	0x88
+#define DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN	0x89
+#define DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN	0x8A
+#define DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN	0x8B
+#define DA7218_DAI_CTRL				0x8C
+#define DA7218_DAI_TDM_CTRL			0x8D
+#define DA7218_DAI_OFFSET_LOWER			0x8E
+#define DA7218_DAI_OFFSET_UPPER			0x8F
+#define DA7218_DAI_CLK_MODE			0x90
+#define DA7218_PLL_CTRL				0x91
+#define DA7218_PLL_FRAC_TOP			0x92
+#define DA7218_PLL_FRAC_BOT			0x93
+#define DA7218_PLL_INTEGER			0x94
+#define DA7218_PLL_STATUS			0x95
+#define DA7218_PLL_REFOSC_CAL			0x98
+#define DA7218_DAC_NG_CTRL			0x9C
+#define DA7218_DAC_NG_SETUP_TIME		0x9D
+#define DA7218_DAC_NG_OFF_THRESH		0x9E
+#define DA7218_DAC_NG_ON_THRESH			0x9F
+#define DA7218_TONE_GEN_CFG1			0xA0
+#define DA7218_TONE_GEN_CFG2			0xA1
+#define DA7218_TONE_GEN_FREQ1_L			0xA2
+#define DA7218_TONE_GEN_FREQ1_U			0xA3
+#define DA7218_TONE_GEN_FREQ2_L			0xA4
+#define DA7218_TONE_GEN_FREQ2_U			0xA5
+#define DA7218_TONE_GEN_CYCLES			0xA6
+#define DA7218_TONE_GEN_ON_PER			0xA7
+#define DA7218_TONE_GEN_OFF_PER			0xA8
+#define DA7218_CP_CTRL				0xAC
+#define DA7218_CP_DELAY				0xAD
+#define DA7218_CP_VOL_THRESHOLD1		0xAE
+#define DA7218_MIC_1_CTRL			0xB4
+#define DA7218_MIC_1_GAIN			0xB5
+#define DA7218_MIC_1_SELECT			0xB7
+#define DA7218_MIC_2_CTRL			0xB8
+#define DA7218_MIC_2_GAIN			0xB9
+#define DA7218_MIC_2_SELECT			0xBB
+#define DA7218_IN_1_HPF_FILTER_CTRL		0xBC
+#define DA7218_IN_2_HPF_FILTER_CTRL		0xBD
+#define DA7218_ADC_1_CTRL			0xC0
+#define DA7218_ADC_2_CTRL			0xC1
+#define DA7218_ADC_MODE				0xC2
+#define DA7218_MIXOUT_L_CTRL			0xCC
+#define DA7218_MIXOUT_L_GAIN			0xCD
+#define DA7218_MIXOUT_R_CTRL			0xCE
+#define DA7218_MIXOUT_R_GAIN			0xCF
+#define DA7218_HP_L_CTRL			0xD0
+#define DA7218_HP_L_GAIN			0xD1
+#define DA7218_HP_R_CTRL			0xD2
+#define DA7218_HP_R_GAIN			0xD3
+#define DA7218_HP_SNGL_CTRL			0xD4
+#define DA7218_HP_DIFF_CTRL			0xD5
+#define DA7218_HP_DIFF_UNLOCK			0xD7
+#define DA7218_HPLDET_JACK			0xD8
+#define DA7218_HPLDET_CTRL			0xD9
+#define DA7218_HPLDET_TEST			0xDA
+#define DA7218_REFERENCES			0xDC
+#define DA7218_IO_CTRL				0xE0
+#define DA7218_LDO_CTRL				0xE1
+#define DA7218_SIDETONE_CTRL			0xE4
+#define DA7218_SIDETONE_IN_SELECT		0xE5
+#define DA7218_SIDETONE_GAIN			0xE6
+#define DA7218_DROUTING_ST_OUTFILT_1L		0xE8
+#define DA7218_DROUTING_ST_OUTFILT_1R		0xE9
+#define DA7218_SIDETONE_BIQ_3STAGE_DATA		0xEA
+#define DA7218_SIDETONE_BIQ_3STAGE_ADDR		0xEB
+#define DA7218_EVENT_STATUS			0xEC
+#define DA7218_EVENT				0xED
+#define DA7218_EVENT_MASK			0xEE
+#define DA7218_DMIC_1_CTRL			0xF0
+#define DA7218_DMIC_2_CTRL			0xF1
+#define DA7218_IN_1L_GAIN			0xF4
+#define DA7218_IN_1R_GAIN			0xF5
+#define DA7218_IN_2L_GAIN			0xF6
+#define DA7218_IN_2R_GAIN			0xF7
+#define DA7218_OUT_1L_GAIN			0xF8
+#define DA7218_OUT_1R_GAIN			0xF9
+#define DA7218_MICBIAS_CTRL			0xFC
+#define DA7218_MICBIAS_EN			0xFD
+
+
+/*
+ * Bit Fields
+ */
+
+#define DA7218_SWITCH_EN_MAX		0x1
+
+/* DA7218_SYSTEM_ACTIVE = 0x0 */
+#define DA7218_SYSTEM_ACTIVE_SHIFT	0
+#define DA7218_SYSTEM_ACTIVE_MASK	(0x1 << 0)
+
+/* DA7218_CIF_CTRL = 0x1 */
+#define DA7218_CIF_I2C_WRITE_MODE_SHIFT	0
+#define DA7218_CIF_I2C_WRITE_MODE_MASK	(0x1 << 0)
+
+/* DA7218_CHIP_ID1 = 0x4 */
+#define DA7218_CHIP_ID1_SHIFT	0
+#define DA7218_CHIP_ID1_MASK	(0xFF << 0)
+
+/* DA7218_CHIP_ID2 = 0x5 */
+#define DA7218_CHIP_ID2_SHIFT	0
+#define DA7218_CHIP_ID2_MASK	(0xFF << 0)
+
+/* DA7218_CHIP_REVISION = 0x6 */
+#define DA7218_CHIP_MINOR_SHIFT	0
+#define DA7218_CHIP_MINOR_MASK	(0xF << 0)
+#define DA7218_CHIP_MAJOR_SHIFT	4
+#define DA7218_CHIP_MAJOR_MASK	(0xF << 4)
+
+/* DA7218_SPARE1 = 0x7 */
+#define DA7218_SPARE1_SHIFT	0
+#define DA7218_SPARE1_MASK	(0xFF << 0)
+
+/* DA7218_STATUS1 = 0x8 */
+#define DA7218_STATUS_SPARE1_SHIFT	0
+#define DA7218_STATUS_SPARE1_MASK	(0xFF << 0)
+
+/* DA7218_SOFT_RESET = 0x9 */
+#define DA7218_CIF_REG_SOFT_RESET_SHIFT	7
+#define DA7218_CIF_REG_SOFT_RESET_MASK	(0x1 << 7)
+
+/* DA7218_SR = 0xB */
+#define DA7218_SR_ADC_SHIFT	0
+#define DA7218_SR_ADC_MASK	(0xF << 0)
+#define DA7218_SR_DAC_SHIFT	4
+#define DA7218_SR_DAC_MASK	(0xF << 4)
+#define DA7218_SR_8000		0x01
+#define DA7218_SR_11025		0x02
+#define DA7218_SR_12000		0x03
+#define DA7218_SR_16000		0x05
+#define DA7218_SR_22050		0x06
+#define DA7218_SR_24000		0x07
+#define DA7218_SR_32000		0x09
+#define DA7218_SR_44100		0x0A
+#define DA7218_SR_48000		0x0B
+#define DA7218_SR_88200		0x0E
+#define DA7218_SR_96000		0x0F
+
+/* DA7218_PC_COUNT = 0xC */
+#define DA7218_PC_FREERUN_SHIFT		0
+#define DA7218_PC_FREERUN_MASK		(0x1 << 0)
+#define DA7218_PC_RESYNC_AUTO_SHIFT	1
+#define DA7218_PC_RESYNC_AUTO_MASK	(0x1 << 1)
+
+/* DA7218_GAIN_RAMP_CTRL = 0xD */
+#define DA7218_GAIN_RAMP_RATE_SHIFT	0
+#define DA7218_GAIN_RAMP_RATE_MASK	(0x3 << 0)
+#define DA7218_GAIN_RAMP_RATE_MAX	4
+
+/* DA7218_CIF_TIMEOUT_CTRL = 0x10 */
+#define DA7218_I2C_TIMEOUT_EN_SHIFT	0
+#define DA7218_I2C_TIMEOUT_EN_MASK	(0x1 << 0)
+
+/* DA7218_SYSTEM_MODES_INPUT = 0x14 */
+#define DA7218_MODE_SUBMIT_SHIFT	0
+#define DA7218_MODE_SUBMIT_MASK		(0x1 << 0)
+#define DA7218_ADC_MODE_SHIFT		1
+#define DA7218_ADC_MODE_MASK		(0x7F << 1)
+
+/* DA7218_SYSTEM_MODES_OUTPUT = 0x15 */
+#define DA7218_MODE_SUBMIT_SHIFT	0
+#define DA7218_MODE_SUBMIT_MASK		(0x1 << 0)
+#define DA7218_DAC_MODE_SHIFT		1
+#define DA7218_DAC_MODE_MASK		(0x7F << 1)
+
+/* DA7218_SYSTEM_STATUS = 0x16 */
+#define DA7218_SC1_BUSY_SHIFT	0
+#define DA7218_SC1_BUSY_MASK	(0x1 << 0)
+#define DA7218_SC2_BUSY_SHIFT	1
+#define DA7218_SC2_BUSY_MASK	(0x1 << 1)
+
+/* DA7218_IN_1L_FILTER_CTRL = 0x18 */
+#define DA7218_IN_1L_RAMP_EN_SHIFT	5
+#define DA7218_IN_1L_RAMP_EN_MASK	(0x1 << 5)
+#define DA7218_IN_1L_MUTE_EN_SHIFT	6
+#define DA7218_IN_1L_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_IN_1L_FILTER_EN_SHIFT	7
+#define DA7218_IN_1L_FILTER_EN_MASK	(0x1 << 7)
+
+/* DA7218_IN_1R_FILTER_CTRL = 0x19 */
+#define DA7218_IN_1R_RAMP_EN_SHIFT	5
+#define DA7218_IN_1R_RAMP_EN_MASK	(0x1 << 5)
+#define DA7218_IN_1R_MUTE_EN_SHIFT	6
+#define DA7218_IN_1R_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_IN_1R_FILTER_EN_SHIFT	7
+#define DA7218_IN_1R_FILTER_EN_MASK	(0x1 << 7)
+
+/* DA7218_IN_2L_FILTER_CTRL = 0x1A */
+#define DA7218_IN_2L_RAMP_EN_SHIFT	5
+#define DA7218_IN_2L_RAMP_EN_MASK	(0x1 << 5)
+#define DA7218_IN_2L_MUTE_EN_SHIFT	6
+#define DA7218_IN_2L_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_IN_2L_FILTER_EN_SHIFT	7
+#define DA7218_IN_2L_FILTER_EN_MASK	(0x1 << 7)
+
+/* DA7218_IN_2R_FILTER_CTRL = 0x1B */
+#define DA7218_IN_2R_RAMP_EN_SHIFT	5
+#define DA7218_IN_2R_RAMP_EN_MASK	(0x1 << 5)
+#define DA7218_IN_2R_MUTE_EN_SHIFT	6
+#define DA7218_IN_2R_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_IN_2R_FILTER_EN_SHIFT	7
+#define DA7218_IN_2R_FILTER_EN_MASK	(0x1 << 7)
+
+/* DA7218_OUT_1L_FILTER_CTRL = 0x20 */
+#define DA7218_OUT_1L_BIQ_5STAGE_SEL_SHIFT	3
+#define DA7218_OUT_1L_BIQ_5STAGE_SEL_MASK	(0x1 << 3)
+#define DA7218_OUT_BIQ_5STAGE_SEL_MAX		2
+#define DA7218_OUT_1L_SUBRANGE_EN_SHIFT		4
+#define DA7218_OUT_1L_SUBRANGE_EN_MASK		(0x1 << 4)
+#define DA7218_OUT_1L_RAMP_EN_SHIFT		5
+#define DA7218_OUT_1L_RAMP_EN_MASK		(0x1 << 5)
+#define DA7218_OUT_1L_MUTE_EN_SHIFT		6
+#define DA7218_OUT_1L_MUTE_EN_MASK		(0x1 << 6)
+#define DA7218_OUT_1L_FILTER_EN_SHIFT		7
+#define DA7218_OUT_1L_FILTER_EN_MASK		(0x1 << 7)
+
+/* DA7218_OUT_1R_FILTER_CTRL = 0x21 */
+#define DA7218_OUT_1R_BIQ_5STAGE_SEL_SHIFT	3
+#define DA7218_OUT_1R_BIQ_5STAGE_SEL_MASK	(0x1 << 3)
+#define DA7218_OUT_1R_SUBRANGE_EN_SHIFT		4
+#define DA7218_OUT_1R_SUBRANGE_EN_MASK		(0x1 << 4)
+#define DA7218_OUT_1R_RAMP_EN_SHIFT		5
+#define DA7218_OUT_1R_RAMP_EN_MASK		(0x1 << 5)
+#define DA7218_OUT_1R_MUTE_EN_SHIFT		6
+#define DA7218_OUT_1R_MUTE_EN_MASK		(0x1 << 6)
+#define DA7218_OUT_1R_FILTER_EN_SHIFT		7
+#define DA7218_OUT_1R_FILTER_EN_MASK		(0x1 << 7)
+
+/* DA7218_OUT_1_HPF_FILTER_CTRL = 0x24 */
+#define DA7218_OUT_1_VOICE_HPF_CORNER_SHIFT	0
+#define DA7218_OUT_1_VOICE_HPF_CORNER_MASK	(0x7 << 0)
+#define DA7218_VOICE_HPF_CORNER_MAX		8
+#define DA7218_OUT_1_VOICE_EN_SHIFT		3
+#define DA7218_OUT_1_VOICE_EN_MASK		(0x1 << 3)
+#define DA7218_OUT_1_AUDIO_HPF_CORNER_SHIFT	4
+#define DA7218_OUT_1_AUDIO_HPF_CORNER_MASK	(0x3 << 4)
+#define DA7218_AUDIO_HPF_CORNER_MAX		4
+#define DA7218_OUT_1_HPF_EN_SHIFT		7
+#define DA7218_OUT_1_HPF_EN_MASK		(0x1 << 7)
+#define DA7218_HPF_MODE_SHIFT			0
+#define DA7218_HPF_DISABLED			((0x0 << 3) | (0x0 << 7))
+#define DA7218_HPF_AUDIO_EN			((0x0 << 3) | (0x1 << 7))
+#define DA7218_HPF_VOICE_EN			((0x1 << 3) | (0x1 << 7))
+#define DA7218_HPF_MODE_MASK			((0x1 << 3) | (0x1 << 7))
+#define DA7218_HPF_MODE_MAX			3
+
+/* DA7218_OUT_1_EQ_12_FILTER_CTRL = 0x25 */
+#define DA7218_OUT_1_EQ_BAND1_SHIFT	0
+#define DA7218_OUT_1_EQ_BAND1_MASK	(0xF << 0)
+#define DA7218_OUT_EQ_BAND_MAX		0xF
+#define DA7218_OUT_1_EQ_BAND2_SHIFT	4
+#define DA7218_OUT_1_EQ_BAND2_MASK	(0xF << 4)
+
+/* DA7218_OUT_1_EQ_34_FILTER_CTRL = 0x26 */
+#define DA7218_OUT_1_EQ_BAND3_SHIFT	0
+#define DA7218_OUT_1_EQ_BAND3_MASK	(0xF << 0)
+#define DA7218_OUT_1_EQ_BAND4_SHIFT	4
+#define DA7218_OUT_1_EQ_BAND4_MASK	(0xF << 4)
+
+/* DA7218_OUT_1_EQ_5_FILTER_CTRL = 0x27 */
+#define DA7218_OUT_1_EQ_BAND5_SHIFT	0
+#define DA7218_OUT_1_EQ_BAND5_MASK	(0xF << 0)
+#define DA7218_OUT_1_EQ_EN_SHIFT	7
+#define DA7218_OUT_1_EQ_EN_MASK		(0x1 << 7)
+
+/* DA7218_OUT_1_BIQ_5STAGE_CTRL = 0x28 */
+#define DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_SHIFT	6
+#define DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_SHIFT	7
+#define DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_MASK	(0x1 << 7)
+
+/* DA7218_OUT_1_BIQ_5STAGE_DATA = 0x29 */
+#define DA7218_OUT_1_BIQ_5STAGE_DATA_SHIFT	0
+#define DA7218_OUT_1_BIQ_5STAGE_DATA_MASK	(0xFF << 0)
+
+/* DA7218_OUT_1_BIQ_5STAGE_ADDR = 0x2A */
+#define DA7218_OUT_1_BIQ_5STAGE_ADDR_SHIFT	0
+#define DA7218_OUT_1_BIQ_5STAGE_ADDR_MASK	(0x3F << 0)
+#define DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE	50
+
+/* DA7218_MIXIN_1_CTRL = 0x2C */
+#define DA7218_MIXIN_1_MIX_SEL_SHIFT		3
+#define DA7218_MIXIN_1_MIX_SEL_MASK		(0x1 << 3)
+#define DA7218_MIXIN_1_AMP_ZC_EN_SHIFT		4
+#define DA7218_MIXIN_1_AMP_ZC_EN_MASK		(0x1 << 4)
+#define DA7218_MIXIN_1_AMP_RAMP_EN_SHIFT	5
+#define DA7218_MIXIN_1_AMP_RAMP_EN_MASK		(0x1 << 5)
+#define DA7218_MIXIN_1_AMP_MUTE_EN_SHIFT	6
+#define DA7218_MIXIN_1_AMP_MUTE_EN_MASK		(0x1 << 6)
+#define DA7218_MIXIN_1_AMP_EN_SHIFT		7
+#define DA7218_MIXIN_1_AMP_EN_MASK		(0x1 << 7)
+
+/* DA7218_MIXIN_1_GAIN = 0x2D */
+#define DA7218_MIXIN_1_AMP_GAIN_SHIFT	0
+#define DA7218_MIXIN_1_AMP_GAIN_MASK	(0xF << 0)
+#define DA7218_MIXIN_AMP_GAIN_MAX	0xF
+
+/* DA7218_MIXIN_2_CTRL = 0x2E */
+#define DA7218_MIXIN_2_MIX_SEL_SHIFT		3
+#define DA7218_MIXIN_2_MIX_SEL_MASK		(0x1 << 3)
+#define DA7218_MIXIN_2_AMP_ZC_EN_SHIFT		4
+#define DA7218_MIXIN_2_AMP_ZC_EN_MASK		(0x1 << 4)
+#define DA7218_MIXIN_2_AMP_RAMP_EN_SHIFT	5
+#define DA7218_MIXIN_2_AMP_RAMP_EN_MASK		(0x1 << 5)
+#define DA7218_MIXIN_2_AMP_MUTE_EN_SHIFT	6
+#define DA7218_MIXIN_2_AMP_MUTE_EN_MASK		(0x1 << 6)
+#define DA7218_MIXIN_2_AMP_EN_SHIFT		7
+#define DA7218_MIXIN_2_AMP_EN_MASK		(0x1 << 7)
+
+/* DA7218_MIXIN_2_GAIN = 0x2F */
+#define DA7218_MIXIN_2_AMP_GAIN_SHIFT	0
+#define DA7218_MIXIN_2_AMP_GAIN_MASK	(0xF << 0)
+
+/* DA7218_ALC_CTRL1 = 0x30 */
+#define DA7218_ALC_EN_SHIFT		0
+#define DA7218_ALC_EN_MASK		(0xF << 0)
+#define DA7218_ALC_CHAN1_L_EN_SHIFT	0
+#define DA7218_ALC_CHAN1_R_EN_SHIFT	1
+#define DA7218_ALC_CHAN2_L_EN_SHIFT	2
+#define DA7218_ALC_CHAN2_R_EN_SHIFT	3
+#define DA7218_ALC_SYNC_MODE_SHIFT	4
+#define DA7218_ALC_SYNC_MODE_MASK	(0xF << 4)
+#define DA7218_ALC_SYNC_MODE_CH1	(0x1 << 4)
+#define DA7218_ALC_SYNC_MODE_CH2	(0x4 << 4)
+
+/* DA7218_ALC_CTRL2 = 0x31 */
+#define DA7218_ALC_ATTACK_SHIFT		0
+#define DA7218_ALC_ATTACK_MASK		(0xF << 0)
+#define DA7218_ALC_ATTACK_MAX		13
+#define DA7218_ALC_RELEASE_SHIFT	4
+#define DA7218_ALC_RELEASE_MASK		(0xF << 4)
+#define DA7218_ALC_RELEASE_MAX		11
+
+/* DA7218_ALC_CTRL3 = 0x32 */
+#define DA7218_ALC_HOLD_SHIFT	0
+#define DA7218_ALC_HOLD_MASK	(0xF << 0)
+#define DA7218_ALC_HOLD_MAX	16
+
+/* DA7218_ALC_NOISE = 0x33 */
+#define DA7218_ALC_NOISE_SHIFT		0
+#define DA7218_ALC_NOISE_MASK		(0x3F << 0)
+#define DA7218_ALC_THRESHOLD_MAX	0x3F
+
+/* DA7218_ALC_TARGET_MIN = 0x34 */
+#define DA7218_ALC_THRESHOLD_MIN_SHIFT	0
+#define DA7218_ALC_THRESHOLD_MIN_MASK	(0x3F << 0)
+
+/* DA7218_ALC_TARGET_MAX = 0x35 */
+#define DA7218_ALC_THRESHOLD_MAX_SHIFT	0
+#define DA7218_ALC_THRESHOLD_MAX_MASK	(0x3F << 0)
+
+/* DA7218_ALC_GAIN_LIMITS = 0x36 */
+#define DA7218_ALC_ATTEN_MAX_SHIFT	0
+#define DA7218_ALC_ATTEN_MAX_MASK	(0xF << 0)
+#define DA7218_ALC_ATTEN_GAIN_MAX	0xF
+#define DA7218_ALC_GAIN_MAX_SHIFT	4
+#define DA7218_ALC_GAIN_MAX_MASK	(0xF << 4)
+
+/* DA7218_ALC_ANA_GAIN_LIMITS = 0x37 */
+#define DA7218_ALC_ANA_GAIN_MIN_SHIFT	0
+#define DA7218_ALC_ANA_GAIN_MIN_MASK	(0x7 << 0)
+#define DA7218_ALC_ANA_GAIN_MIN		0x1
+#define DA7218_ALC_ANA_GAIN_MAX		0x7
+#define DA7218_ALC_ANA_GAIN_MAX_SHIFT	4
+#define DA7218_ALC_ANA_GAIN_MAX_MASK	(0x7 << 4)
+
+/* DA7218_ALC_ANTICLIP_CTRL = 0x38 */
+#define DA7218_ALC_ANTICLIP_STEP_SHIFT	0
+#define DA7218_ALC_ANTICLIP_STEP_MASK	(0x3 << 0)
+#define DA7218_ALC_ANTICLIP_STEP_MAX	4
+#define DA7218_ALC_ANTICLIP_EN_SHIFT	7
+#define DA7218_ALC_ANTICLIP_EN_MASK	(0x1 << 7)
+
+/* DA7218_AGS_ENABLE = 0x3C */
+#define DA7218_AGS_ENABLE_SHIFT		0
+#define DA7218_AGS_ENABLE_MASK		(0x3 << 0)
+#define DA7218_AGS_ENABLE_CHAN1_SHIFT	0
+#define DA7218_AGS_ENABLE_CHAN2_SHIFT	1
+
+/* DA7218_AGS_TRIGGER = 0x3D */
+#define DA7218_AGS_TRIGGER_SHIFT	0
+#define DA7218_AGS_TRIGGER_MASK		(0xF << 0)
+#define DA7218_AGS_TRIGGER_MAX		0xF
+
+/* DA7218_AGS_ATT_MAX = 0x3E */
+#define DA7218_AGS_ATT_MAX_SHIFT	0
+#define DA7218_AGS_ATT_MAX_MASK		(0x7 << 0)
+#define DA7218_AGS_ATT_MAX_MAX		0x7
+
+/* DA7218_AGS_TIMEOUT = 0x3F */
+#define DA7218_AGS_TIMEOUT_EN_SHIFT	0
+#define DA7218_AGS_TIMEOUT_EN_MASK	(0x1 << 0)
+
+/* DA7218_AGS_ANTICLIP_CTRL = 0x40 */
+#define DA7218_AGS_ANTICLIP_EN_SHIFT	7
+#define DA7218_AGS_ANTICLIP_EN_MASK	(0x1 << 7)
+
+/* DA7218_CALIB_CTRL = 0x44 */
+#define DA7218_CALIB_OFFSET_EN_SHIFT	0
+#define DA7218_CALIB_OFFSET_EN_MASK	(0x1 << 0)
+#define DA7218_CALIB_AUTO_EN_SHIFT	2
+#define DA7218_CALIB_AUTO_EN_MASK	(0x1 << 2)
+#define DA7218_CALIB_OVERFLOW_SHIFT	3
+#define DA7218_CALIB_OVERFLOW_MASK	(0x1 << 3)
+
+/* DA7218_CALIB_OFFSET_AUTO_M_1 = 0x45 */
+#define DA7218_CALIB_OFFSET_AUTO_M_1_SHIFT	0
+#define DA7218_CALIB_OFFSET_AUTO_M_1_MASK	(0xFF << 0)
+
+/* DA7218_CALIB_OFFSET_AUTO_U_1 = 0x46 */
+#define DA7218_CALIB_OFFSET_AUTO_U_1_SHIFT	0
+#define DA7218_CALIB_OFFSET_AUTO_U_1_MASK	(0xF << 0)
+
+/* DA7218_CALIB_OFFSET_AUTO_M_2 = 0x47 */
+#define DA7218_CALIB_OFFSET_AUTO_M_2_SHIFT	0
+#define DA7218_CALIB_OFFSET_AUTO_M_2_MASK	(0xFF << 0)
+
+/* DA7218_CALIB_OFFSET_AUTO_U_2 = 0x48 */
+#define DA7218_CALIB_OFFSET_AUTO_U_2_SHIFT	0
+#define DA7218_CALIB_OFFSET_AUTO_U_2_MASK	(0xF << 0)
+
+/* DA7218_ENV_TRACK_CTRL = 0x4C */
+#define DA7218_INTEG_ATTACK_SHIFT	0
+#define DA7218_INTEG_ATTACK_MASK	(0x3 << 0)
+#define DA7218_INTEG_RELEASE_SHIFT	4
+#define DA7218_INTEG_RELEASE_MASK	(0x3 << 4)
+#define DA7218_INTEG_MAX		4
+
+/* DA7218_LVL_DET_CTRL = 0x50 */
+#define DA7218_LVL_DET_EN_SHIFT		0
+#define DA7218_LVL_DET_EN_MASK		(0xF << 0)
+#define DA7218_LVL_DET_EN_CHAN1L_SHIFT	0
+#define DA7218_LVL_DET_EN_CHAN1R_SHIFT	1
+#define DA7218_LVL_DET_EN_CHAN2L_SHIFT	2
+#define DA7218_LVL_DET_EN_CHAN2R_SHIFT	3
+
+/* DA7218_LVL_DET_LEVEL = 0x51 */
+#define DA7218_LVL_DET_LEVEL_SHIFT	0
+#define DA7218_LVL_DET_LEVEL_MASK	(0x7F << 0)
+#define DA7218_LVL_DET_LEVEL_MAX	0x7F
+
+/* DA7218_DGS_TRIGGER = 0x54 */
+#define DA7218_DGS_TRIGGER_LVL_SHIFT	0
+#define DA7218_DGS_TRIGGER_LVL_MASK	(0x3F << 0)
+#define DA7218_DGS_TRIGGER_MAX		0x3F
+
+/* DA7218_DGS_ENABLE = 0x55 */
+#define DA7218_DGS_ENABLE_SHIFT		0
+#define DA7218_DGS_ENABLE_MASK		(0x3 << 0)
+#define DA7218_DGS_ENABLE_L_SHIFT	0
+#define DA7218_DGS_ENABLE_R_SHIFT	1
+
+/* DA7218_DGS_RISE_FALL = 0x56 */
+#define DA7218_DGS_RISE_COEFF_SHIFT	0
+#define DA7218_DGS_RISE_COEFF_MASK	(0x7 << 0)
+#define DA7218_DGS_RISE_COEFF_MAX	7
+#define DA7218_DGS_FALL_COEFF_SHIFT	4
+#define DA7218_DGS_FALL_COEFF_MASK	(0x7 << 4)
+#define DA7218_DGS_FALL_COEFF_MAX	8
+
+/* DA7218_DGS_SYNC_DELAY = 0x57 */
+#define DA7218_DGS_SYNC_DELAY_SHIFT	0
+#define DA7218_DGS_SYNC_DELAY_MASK	(0xFF << 0)
+#define DA7218_DGS_SYNC_DELAY_MAX	0xFF
+
+/* DA7218_DGS_SYNC_DELAY2 = 0x58 */
+#define DA7218_DGS_SYNC_DELAY2_SHIFT	0
+#define DA7218_DGS_SYNC_DELAY2_MASK	(0xFF << 0)
+
+/* DA7218_DGS_SYNC_DELAY3 = 0x59 */
+#define DA7218_DGS_SYNC_DELAY3_SHIFT	0
+#define DA7218_DGS_SYNC_DELAY3_MASK	(0x7F << 0)
+#define DA7218_DGS_SYNC_DELAY3_MAX	0x7F
+
+/* DA7218_DGS_LEVELS = 0x5A */
+#define DA7218_DGS_ANTICLIP_LVL_SHIFT	0
+#define DA7218_DGS_ANTICLIP_LVL_MASK	(0x7 << 0)
+#define DA7218_DGS_ANTICLIP_LVL_MAX	0x7
+#define DA7218_DGS_SIGNAL_LVL_SHIFT	4
+#define DA7218_DGS_SIGNAL_LVL_MASK	(0xF << 4)
+#define DA7218_DGS_SIGNAL_LVL_MAX	0xF
+
+/* DA7218_DGS_GAIN_CTRL = 0x5B */
+#define DA7218_DGS_STEPS_SHIFT		0
+#define DA7218_DGS_STEPS_MASK		(0x1F << 0)
+#define DA7218_DGS_STEPS_MAX		0x1F
+#define DA7218_DGS_RAMP_EN_SHIFT	5
+#define DA7218_DGS_RAMP_EN_MASK		(0x1 << 5)
+#define DA7218_DGS_SUBR_EN_SHIFT	6
+#define DA7218_DGS_SUBR_EN_MASK		(0x1 << 6)
+
+/* DA7218_DROUTING_OUTDAI_1L = 0x5C */
+#define DA7218_OUTDAI_1L_SRC_SHIFT	0
+#define DA7218_OUTDAI_1L_SRC_MASK	(0x7F << 0)
+#define DA7218_DMIX_SRC_INFILT1L	0
+#define DA7218_DMIX_SRC_INFILT1R	1
+#define DA7218_DMIX_SRC_INFILT2L	2
+#define DA7218_DMIX_SRC_INFILT2R	3
+#define DA7218_DMIX_SRC_TONEGEN		4
+#define DA7218_DMIX_SRC_DAIL		5
+#define DA7218_DMIX_SRC_DAIR		6
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN = 0x5D */
+#define DA7218_OUTDAI_1L_INFILT_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1L_INFILT_1L_GAIN_MASK	(0x1F << 0)
+#define DA7218_DMIX_GAIN_MAX			0x1F
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN = 0x5E */
+#define DA7218_OUTDAI_1L_INFILT_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1L_INFILT_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN = 0x5F */
+#define DA7218_OUTDAI_1L_INFILT_2L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1L_INFILT_2L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN = 0x60 */
+#define DA7218_OUTDAI_1L_INFILT_2R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1L_INFILT_2R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN = 0x61 */
+#define DA7218_OUTDAI_1L_TONEGEN_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1L_TONEGEN_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN = 0x62 */
+#define DA7218_OUTDAI_1L_INDAI_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1L_INDAI_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN = 0x63 */
+#define DA7218_OUTDAI_1L_INDAI_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1L_INDAI_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DROUTING_OUTDAI_1R = 0x64 */
+#define DA7218_OUTDAI_1R_SRC_SHIFT	0
+#define DA7218_OUTDAI_1R_SRC_MASK	(0x7F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN = 0x65 */
+#define DA7218_OUTDAI_1R_INFILT_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1R_INFILT_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN = 0x66 */
+#define DA7218_OUTDAI_1R_INFILT_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1R_INFILT_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN = 0x67 */
+#define DA7218_OUTDAI_1R_INFILT_2L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1R_INFILT_2L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN = 0x68 */
+#define DA7218_OUTDAI_1R_INFILT_2R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1R_INFILT_2R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN = 0x69 */
+#define DA7218_OUTDAI_1R_TONEGEN_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1R_TONEGEN_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN = 0x6A */
+#define DA7218_OUTDAI_1R_INDAI_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1R_INDAI_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN = 0x6B */
+#define DA7218_OUTDAI_1R_INDAI_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_1R_INDAI_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DROUTING_OUTFILT_1L = 0x6C */
+#define DA7218_OUTFILT_1L_SRC_SHIFT	0
+#define DA7218_OUTFILT_1L_SRC_MASK	(0x7F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN = 0x6D */
+#define DA7218_OUTFILT_1L_INFILT_1L_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1L_INFILT_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN = 0x6E */
+#define DA7218_OUTFILT_1L_INFILT_1R_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1L_INFILT_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN = 0x6F */
+#define DA7218_OUTFILT_1L_INFILT_2L_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1L_INFILT_2L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN = 0x70 */
+#define DA7218_OUTFILT_1L_INFILT_2R_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1L_INFILT_2R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN = 0x71 */
+#define DA7218_OUTFILT_1L_TONEGEN_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1L_TONEGEN_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN = 0x72 */
+#define DA7218_OUTFILT_1L_INDAI_1L_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1L_INDAI_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN = 0x73 */
+#define DA7218_OUTFILT_1L_INDAI_1R_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1L_INDAI_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DROUTING_OUTFILT_1R = 0x74 */
+#define DA7218_OUTFILT_1R_SRC_SHIFT	0
+#define DA7218_OUTFILT_1R_SRC_MASK	(0x7F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN = 0x75 */
+#define DA7218_OUTFILT_1R_INFILT_1L_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1R_INFILT_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN = 0x76 */
+#define DA7218_OUTFILT_1R_INFILT_1R_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1R_INFILT_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN = 0x77 */
+#define DA7218_OUTFILT_1R_INFILT_2L_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1R_INFILT_2L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN = 0x78 */
+#define DA7218_OUTFILT_1R_INFILT_2R_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1R_INFILT_2R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN = 0x79 */
+#define DA7218_OUTFILT_1R_TONEGEN_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1R_TONEGEN_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN = 0x7A */
+#define DA7218_OUTFILT_1R_INDAI_1L_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1R_INDAI_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN = 0x7B */
+#define DA7218_OUTFILT_1R_INDAI_1R_GAIN_SHIFT	0
+#define DA7218_OUTFILT_1R_INDAI_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DROUTING_OUTDAI_2L = 0x7C */
+#define DA7218_OUTDAI_2L_SRC_SHIFT	0
+#define DA7218_OUTDAI_2L_SRC_MASK	(0x7F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN = 0x7D */
+#define DA7218_OUTDAI_2L_INFILT_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2L_INFILT_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN = 0x7E */
+#define DA7218_OUTDAI_2L_INFILT_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2L_INFILT_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN = 0x7F */
+#define DA7218_OUTDAI_2L_INFILT_2L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2L_INFILT_2L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN = 0x80 */
+#define DA7218_OUTDAI_2L_INFILT_2R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2L_INFILT_2R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN = 0x81 */
+#define DA7218_OUTDAI_2L_TONEGEN_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2L_TONEGEN_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN = 0x82 */
+#define DA7218_OUTDAI_2L_INDAI_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2L_INDAI_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN = 0x83 */
+#define DA7218_OUTDAI_2L_INDAI_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2L_INDAI_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DROUTING_OUTDAI_2R = 0x84 */
+#define DA7218_OUTDAI_2R_SRC_SHIFT	0
+#define DA7218_OUTDAI_2R_SRC_MASK	(0x7F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN = 0x85 */
+#define DA7218_OUTDAI_2R_INFILT_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2R_INFILT_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN = 0x86 */
+#define DA7218_OUTDAI_2R_INFILT_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2R_INFILT_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN = 0x87 */
+#define DA7218_OUTDAI_2R_INFILT_2L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2R_INFILT_2L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN = 0x88 */
+#define DA7218_OUTDAI_2R_INFILT_2R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2R_INFILT_2R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN = 0x89 */
+#define DA7218_OUTDAI_2R_TONEGEN_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2R_TONEGEN_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN = 0x8A */
+#define DA7218_OUTDAI_2R_INDAI_1L_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2R_INDAI_1L_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN = 0x8B */
+#define DA7218_OUTDAI_2R_INDAI_1R_GAIN_SHIFT	0
+#define DA7218_OUTDAI_2R_INDAI_1R_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DAI_CTRL = 0x8C */
+#define DA7218_DAI_FORMAT_SHIFT		0
+#define DA7218_DAI_FORMAT_MASK		(0x3 << 0)
+#define DA7218_DAI_FORMAT_I2S		(0x0 << 0)
+#define DA7218_DAI_FORMAT_LEFT_J	(0x1 << 0)
+#define DA7218_DAI_FORMAT_RIGHT_J	(0x2 << 0)
+#define DA7218_DAI_FORMAT_DSP		(0x3 << 0)
+#define DA7218_DAI_WORD_LENGTH_SHIFT	2
+#define DA7218_DAI_WORD_LENGTH_MASK	(0x3 << 2)
+#define DA7218_DAI_WORD_LENGTH_S16_LE	(0x0 << 2)
+#define DA7218_DAI_WORD_LENGTH_S20_LE	(0x1 << 2)
+#define DA7218_DAI_WORD_LENGTH_S24_LE	(0x2 << 2)
+#define DA7218_DAI_WORD_LENGTH_S32_LE	(0x3 << 2)
+#define DA7218_DAI_CH_NUM_SHIFT		4
+#define DA7218_DAI_CH_NUM_MASK		(0x7 << 4)
+#define DA7218_DAI_CH_NUM_MAX		4
+#define DA7218_DAI_EN_SHIFT		7
+#define DA7218_DAI_EN_MASK		(0x1 << 7)
+
+/* DA7218_DAI_TDM_CTRL = 0x8D */
+#define DA7218_DAI_TDM_CH_EN_SHIFT	0
+#define DA7218_DAI_TDM_CH_EN_MASK	(0xF << 0)
+#define DA7218_DAI_TDM_MAX_SLOTS	4
+#define DA7218_DAI_OE_SHIFT		6
+#define DA7218_DAI_OE_MASK		(0x1 << 6)
+#define DA7218_DAI_TDM_MODE_EN_SHIFT	7
+#define DA7218_DAI_TDM_MODE_EN_MASK	(0x1 << 7)
+
+/* DA7218_DAI_OFFSET_LOWER = 0x8E */
+#define DA7218_DAI_OFFSET_LOWER_SHIFT	0
+#define DA7218_DAI_OFFSET_LOWER_MASK	(0xFF << 0)
+
+/* DA7218_DAI_OFFSET_UPPER = 0x8F */
+#define DA7218_DAI_OFFSET_UPPER_SHIFT	0
+#define DA7218_DAI_OFFSET_UPPER_MASK	(0x7 << 0)
+
+/* DA7218_DAI_CLK_MODE = 0x90 */
+#define DA7218_DAI_BCLKS_PER_WCLK_SHIFT	0
+#define DA7218_DAI_BCLKS_PER_WCLK_MASK	(0x3 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_32	(0x0 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_64	(0x1 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_128	(0x2 << 0)
+#define DA7218_DAI_BCLKS_PER_WCLK_256	(0x3 << 0)
+#define DA7218_DAI_CLK_POL_SHIFT	2
+#define DA7218_DAI_CLK_POL_MASK		(0x1 << 2)
+#define DA7218_DAI_CLK_POL_INV		(0x1 << 2)
+#define DA7218_DAI_WCLK_POL_SHIFT	3
+#define DA7218_DAI_WCLK_POL_MASK	(0x1 << 3)
+#define DA7218_DAI_WCLK_POL_INV		(0x1 << 3)
+#define DA7218_DAI_WCLK_TRI_STATE_SHIFT	4
+#define DA7218_DAI_WCLK_TRI_STATE_MASK	(0x1 << 4)
+#define DA7218_DAI_CLK_EN_SHIFT		7
+#define DA7218_DAI_CLK_EN_MASK		(0x1 << 7)
+
+/* DA7218_PLL_CTRL = 0x91 */
+#define DA7218_PLL_INDIV_SHIFT		0
+#define DA7218_PLL_INDIV_MASK		(0x7 << 0)
+#define DA7218_PLL_INDIV_2_5_MHZ	(0x0 << 0)
+#define DA7218_PLL_INDIV_5_10_MHZ	(0x1 << 0)
+#define DA7218_PLL_INDIV_10_20_MHZ	(0x2 << 0)
+#define DA7218_PLL_INDIV_20_40_MHZ	(0x3 << 0)
+#define DA7218_PLL_INDIV_40_54_MHZ	(0x4 << 0)
+#define DA7218_PLL_INDIV_2_10_MHZ_VAL	2
+#define DA7218_PLL_INDIV_10_20_MHZ_VAL	4
+#define DA7218_PLL_INDIV_20_40_MHZ_VAL	8
+#define DA7218_PLL_INDIV_40_54_MHZ_VAL	16
+#define DA7218_PLL_MCLK_SQR_EN_SHIFT	4
+#define DA7218_PLL_MCLK_SQR_EN_MASK	(0x1 << 4)
+#define DA7218_PLL_MODE_SHIFT		6
+#define DA7218_PLL_MODE_MASK		(0x3 << 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
+#define DA7218_PLL_FBDIV_FRAC_TOP_MASK	(0x1F << 0)
+
+/* DA7218_PLL_FRAC_BOT = 0x93 */
+#define DA7218_PLL_FBDIV_FRAC_BOT_SHIFT	0
+#define DA7218_PLL_FBDIV_FRAC_BOT_MASK	(0xFF << 0)
+
+/* DA7218_PLL_INTEGER = 0x94 */
+#define DA7218_PLL_FBDIV_INTEGER_SHIFT	0
+#define DA7218_PLL_FBDIV_INTEGER_MASK	(0x7F << 0)
+
+/* DA7218_PLL_STATUS = 0x95 */
+#define DA7218_PLL_SRM_STATUS_SHIFT	0
+#define DA7218_PLL_SRM_STATUS_MASK	(0xFF << 0)
+#define DA7218_PLL_SRM_STATUS_SRM_LOCK	(0x1 << 7)
+
+/* DA7218_PLL_REFOSC_CAL = 0x98 */
+#define DA7218_PLL_REFOSC_CAL_CTRL_SHIFT	0
+#define DA7218_PLL_REFOSC_CAL_CTRL_MASK		(0x1F << 0)
+#define DA7218_PLL_REFOSC_CAL_START_SHIFT	6
+#define DA7218_PLL_REFOSC_CAL_START_MASK	(0x1 << 6)
+#define DA7218_PLL_REFOSC_CAL_EN_SHIFT		7
+#define DA7218_PLL_REFOSC_CAL_EN_MASK		(0x1 << 7)
+
+/* DA7218_DAC_NG_CTRL = 0x9C */
+#define DA7218_DAC_NG_EN_SHIFT	7
+#define DA7218_DAC_NG_EN_MASK	(0x1 << 7)
+
+/* DA7218_DAC_NG_SETUP_TIME = 0x9D */
+#define DA7218_DAC_NG_SETUP_TIME_SHIFT	0
+#define DA7218_DAC_NG_SETUP_TIME_MASK	(0x3 << 0)
+#define DA7218_DAC_NG_SETUP_TIME_MAX	4
+#define DA7218_DAC_NG_RAMPUP_RATE_SHIFT	2
+#define DA7218_DAC_NG_RAMPUP_RATE_MASK	(0x1 << 2)
+#define DA7218_DAC_NG_RAMPUP_RATE_MAX	2
+#define DA7218_DAC_NG_RAMPDN_RATE_SHIFT	3
+#define DA7218_DAC_NG_RAMPDN_RATE_MASK	(0x1 << 3)
+#define DA7218_DAC_NG_RAMPDN_RATE_MAX	2
+
+/* DA7218_DAC_NG_OFF_THRESH = 0x9E */
+#define DA7218_DAC_NG_OFF_THRESHOLD_SHIFT	0
+#define DA7218_DAC_NG_OFF_THRESHOLD_MASK	(0x7 << 0)
+#define DA7218_DAC_NG_THRESHOLD_MAX		0x7
+
+/* DA7218_DAC_NG_ON_THRESH = 0x9F */
+#define DA7218_DAC_NG_ON_THRESHOLD_SHIFT	0
+#define DA7218_DAC_NG_ON_THRESHOLD_MASK		(0x7 << 0)
+
+/* DA7218_TONE_GEN_CFG1 = 0xA0 */
+#define DA7218_DTMF_REG_SHIFT		0
+#define DA7218_DTMF_REG_MASK		(0xF << 0)
+#define DA7218_DTMF_REG_MAX		16
+#define DA7218_DTMF_EN_SHIFT		4
+#define DA7218_DTMF_EN_MASK		(0x1 << 4)
+#define DA7218_START_STOPN_SHIFT	7
+#define DA7218_START_STOPN_MASK		(0x1 << 7)
+
+/* DA7218_TONE_GEN_CFG2 = 0xA1 */
+#define DA7218_SWG_SEL_SHIFT	0
+#define DA7218_SWG_SEL_MASK	(0x3 << 0)
+#define DA7218_SWG_SEL_MAX	4
+
+/* DA7218_TONE_GEN_FREQ1_L = 0xA2 */
+#define DA7218_FREQ1_L_SHIFT	0
+#define DA7218_FREQ1_L_MASK	(0xFF << 0)
+#define DA7218_FREQ_MAX		0xFFFF
+
+/* DA7218_TONE_GEN_FREQ1_U = 0xA3 */
+#define DA7218_FREQ1_U_SHIFT	0
+#define DA7218_FREQ1_U_MASK	(0xFF << 0)
+
+/* DA7218_TONE_GEN_FREQ2_L = 0xA4 */
+#define DA7218_FREQ2_L_SHIFT	0
+#define DA7218_FREQ2_L_MASK	(0xFF << 0)
+
+/* DA7218_TONE_GEN_FREQ2_U = 0xA5 */
+#define DA7218_FREQ2_U_SHIFT	0
+#define DA7218_FREQ2_U_MASK	(0xFF << 0)
+
+/* DA7218_TONE_GEN_CYCLES = 0xA6 */
+#define DA7218_BEEP_CYCLES_SHIFT	0
+#define DA7218_BEEP_CYCLES_MASK		(0x7 << 0)
+
+/* DA7218_TONE_GEN_ON_PER = 0xA7 */
+#define DA7218_BEEP_ON_PER_SHIFT	0
+#define DA7218_BEEP_ON_PER_MASK		(0x3F << 0)
+
+/* DA7218_TONE_GEN_OFF_PER = 0xA8 */
+#define DA7218_BEEP_OFF_PER_SHIFT	0
+#define DA7218_BEEP_OFF_PER_MASK	(0x3F << 0)
+#define DA7218_BEEP_ON_OFF_MAX		0x3F
+
+/* DA7218_CP_CTRL = 0xAC */
+#define DA7218_CP_MOD_SHIFT			2
+#define DA7218_CP_MOD_MASK			(0x3 << 2)
+#define DA7218_CP_MCHANGE_SHIFT			4
+#define DA7218_CP_MCHANGE_MASK			(0x3 << 4)
+#define DA7218_CP_MCHANGE_REL_MASK		0x3
+#define DA7218_CP_MCHANGE_MAX			3
+#define DA7218_CP_MCHANGE_LARGEST_VOL		0x1
+#define DA7218_CP_MCHANGE_DAC_VOL		0x2
+#define DA7218_CP_MCHANGE_SIG_MAG		0x3
+#define DA7218_CP_SMALL_SWITCH_FREQ_EN_SHIFT	6
+#define DA7218_CP_SMALL_SWITCH_FREQ_EN_MASK	(0x1 << 6)
+#define DA7218_CP_EN_SHIFT			7
+#define DA7218_CP_EN_MASK			(0x1 << 7)
+
+/* DA7218_CP_DELAY = 0xAD */
+#define DA7218_CP_FCONTROL_SHIFT	0
+#define DA7218_CP_FCONTROL_MASK		(0x7 << 0)
+#define DA7218_CP_FCONTROL_MAX		6
+#define DA7218_CP_TAU_DELAY_SHIFT	3
+#define DA7218_CP_TAU_DELAY_MASK	(0x7 << 3)
+#define DA7218_CP_TAU_DELAY_MAX		8
+
+/* DA7218_CP_VOL_THRESHOLD1 = 0xAE */
+#define DA7218_CP_THRESH_VDD2_SHIFT	0
+#define DA7218_CP_THRESH_VDD2_MASK	(0x3F << 0)
+#define DA7218_CP_THRESH_VDD2_MAX	0x3F
+
+/* DA7218_MIC_1_CTRL = 0xB4 */
+#define DA7218_MIC_1_AMP_MUTE_EN_SHIFT	6
+#define DA7218_MIC_1_AMP_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_MIC_1_AMP_EN_SHIFT	7
+#define DA7218_MIC_1_AMP_EN_MASK	(0x1 << 7)
+
+/* DA7218_MIC_1_GAIN = 0xB5 */
+#define DA7218_MIC_1_AMP_GAIN_SHIFT	0
+#define DA7218_MIC_1_AMP_GAIN_MASK	(0x7 << 0)
+#define DA7218_MIC_AMP_GAIN_MAX		0x7
+
+/* DA7218_MIC_1_SELECT = 0xB7 */
+#define DA7218_MIC_1_AMP_IN_SEL_SHIFT	0
+#define DA7218_MIC_1_AMP_IN_SEL_MASK	(0x3 << 0)
+
+/* DA7218_MIC_2_CTRL = 0xB8 */
+#define DA7218_MIC_2_AMP_MUTE_EN_SHIFT	6
+#define DA7218_MIC_2_AMP_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_MIC_2_AMP_EN_SHIFT	7
+#define DA7218_MIC_2_AMP_EN_MASK	(0x1 << 7)
+
+/* DA7218_MIC_2_GAIN = 0xB9 */
+#define DA7218_MIC_2_AMP_GAIN_SHIFT	0
+#define DA7218_MIC_2_AMP_GAIN_MASK	(0x7 << 0)
+
+/* DA7218_MIC_2_SELECT = 0xBB */
+#define DA7218_MIC_2_AMP_IN_SEL_SHIFT	0
+#define DA7218_MIC_2_AMP_IN_SEL_MASK	(0x3 << 0)
+
+/* DA7218_IN_1_HPF_FILTER_CTRL = 0xBC */
+#define DA7218_IN_1_VOICE_HPF_CORNER_SHIFT	0
+#define DA7218_IN_1_VOICE_HPF_CORNER_MASK	(0x7 << 0)
+#define DA7218_IN_VOICE_HPF_CORNER_MAX		8
+#define DA7218_IN_1_VOICE_EN_SHIFT		3
+#define DA7218_IN_1_VOICE_EN_MASK		(0x1 << 3)
+#define DA7218_IN_1_AUDIO_HPF_CORNER_SHIFT	4
+#define DA7218_IN_1_AUDIO_HPF_CORNER_MASK	(0x3 << 4)
+#define DA7218_IN_1_HPF_EN_SHIFT		7
+#define DA7218_IN_1_HPF_EN_MASK			(0x1 << 7)
+
+/* DA7218_IN_2_HPF_FILTER_CTRL = 0xBD */
+#define DA7218_IN_2_VOICE_HPF_CORNER_SHIFT	0
+#define DA7218_IN_2_VOICE_HPF_CORNER_MASK	(0x7 << 0)
+#define DA7218_IN_2_VOICE_EN_SHIFT		3
+#define DA7218_IN_2_VOICE_EN_MASK		(0x1 << 3)
+#define DA7218_IN_2_AUDIO_HPF_CORNER_SHIFT	4
+#define DA7218_IN_2_AUDIO_HPF_CORNER_MASK	(0x3 << 4)
+#define DA7218_IN_2_HPF_EN_SHIFT		7
+#define DA7218_IN_2_HPF_EN_MASK			(0x1 << 7)
+
+/* DA7218_ADC_1_CTRL = 0xC0 */
+#define DA7218_ADC_1_AAF_EN_SHIFT	2
+#define DA7218_ADC_1_AAF_EN_MASK	(0x1 << 2)
+
+/* DA7218_ADC_2_CTRL = 0xC1 */
+#define DA7218_ADC_2_AAF_EN_SHIFT	2
+#define DA7218_ADC_2_AAF_EN_MASK	(0x1 << 2)
+
+/* DA7218_ADC_MODE = 0xC2 */
+#define DA7218_ADC_LP_MODE_SHIFT		0
+#define DA7218_ADC_LP_MODE_MASK			(0x1 << 0)
+#define DA7218_ADC_LVLDET_MODE_SHIFT		1
+#define DA7218_ADC_LVLDET_MODE_MASK		(0x1 << 1)
+#define DA7218_ADC_LVLDET_AUTO_EXIT_SHIFT	2
+#define DA7218_ADC_LVLDET_AUTO_EXIT_MASK	(0x1 << 2)
+
+/* DA7218_MIXOUT_L_CTRL = 0xCC */
+#define DA7218_MIXOUT_L_AMP_EN_SHIFT	7
+#define DA7218_MIXOUT_L_AMP_EN_MASK	(0x1 << 7)
+
+/* DA7218_MIXOUT_L_GAIN = 0xCD */
+#define DA7218_MIXOUT_L_AMP_GAIN_SHIFT	0
+#define DA7218_MIXOUT_L_AMP_GAIN_MASK	(0x3 << 0)
+#define DA7218_MIXOUT_AMP_GAIN_MIN	0x1
+#define DA7218_MIXOUT_AMP_GAIN_MAX	0x3
+
+/* DA7218_MIXOUT_R_CTRL = 0xCE */
+#define DA7218_MIXOUT_R_AMP_EN_SHIFT	7
+#define DA7218_MIXOUT_R_AMP_EN_MASK	(0x1 << 7)
+
+/* DA7218_MIXOUT_R_GAIN = 0xCF */
+#define DA7218_MIXOUT_R_AMP_GAIN_SHIFT	0
+#define DA7218_MIXOUT_R_AMP_GAIN_MASK	(0x3 << 0)
+
+/* DA7218_HP_L_CTRL = 0xD0 */
+#define DA7218_HP_L_AMP_MIN_GAIN_EN_SHIFT	2
+#define DA7218_HP_L_AMP_MIN_GAIN_EN_MASK	(0x1 << 2)
+#define DA7218_HP_L_AMP_OE_SHIFT		3
+#define DA7218_HP_L_AMP_OE_MASK			(0x1 << 3)
+#define DA7218_HP_L_AMP_ZC_EN_SHIFT		4
+#define DA7218_HP_L_AMP_ZC_EN_MASK		(0x1 << 4)
+#define DA7218_HP_L_AMP_RAMP_EN_SHIFT		5
+#define DA7218_HP_L_AMP_RAMP_EN_MASK		(0x1 << 5)
+#define DA7218_HP_L_AMP_MUTE_EN_SHIFT		6
+#define DA7218_HP_L_AMP_MUTE_EN_MASK		(0x1 << 6)
+#define DA7218_HP_L_AMP_EN_SHIFT		7
+#define DA7218_HP_L_AMP_EN_MASK			(0x1 << 7)
+#define DA7218_HP_AMP_OE_MASK			(0x1 << 3)
+
+/* DA7218_HP_L_GAIN = 0xD1 */
+#define DA7218_HP_L_AMP_GAIN_SHIFT	0
+#define DA7218_HP_L_AMP_GAIN_MASK	(0x3F << 0)
+#define DA7218_HP_AMP_GAIN_MIN		0x15
+#define DA7218_HP_AMP_GAIN_MAX		0x3F
+
+/* DA7218_HP_R_CTRL = 0xD2 */
+#define DA7218_HP_R_AMP_MIN_GAIN_EN_SHIFT	2
+#define DA7218_HP_R_AMP_MIN_GAIN_EN_MASK	(0x1 << 2)
+#define DA7218_HP_R_AMP_OE_SHIFT		3
+#define DA7218_HP_R_AMP_OE_MASK			(0x1 << 3)
+#define DA7218_HP_R_AMP_ZC_EN_SHIFT		4
+#define DA7218_HP_R_AMP_ZC_EN_MASK		(0x1 << 4)
+#define DA7218_HP_R_AMP_RAMP_EN_SHIFT		5
+#define DA7218_HP_R_AMP_RAMP_EN_MASK		(0x1 << 5)
+#define DA7218_HP_R_AMP_MUTE_EN_SHIFT		6
+#define DA7218_HP_R_AMP_MUTE_EN_MASK		(0x1 << 6)
+#define DA7218_HP_R_AMP_EN_SHIFT		7
+#define DA7218_HP_R_AMP_EN_MASK			(0x1 << 7)
+
+/* DA7218_HP_R_GAIN = 0xD3 */
+#define DA7218_HP_R_AMP_GAIN_SHIFT	0
+#define DA7218_HP_R_AMP_GAIN_MASK	(0x3F << 0)
+
+/* DA7218_HP_SNGL_CTRL = 0xD4 */
+#define DA7218_HP_AMP_STEREO_DETECT_STATUS_SHIFT	0
+#define DA7218_HP_AMP_STEREO_DETECT_STATUS_MASK		(0x1 << 0)
+#define DA7218_HPL_AMP_LOAD_DETECT_STATUS_SHIFT		1
+#define DA7218_HPL_AMP_LOAD_DETECT_STATUS_MASK		(0x1 << 1)
+#define DA7218_HPR_AMP_LOAD_DETECT_STATUS_SHIFT		2
+#define DA7218_HPR_AMP_LOAD_DETECT_STATUS_MASK		(0x1 << 2)
+#define DA7218_HP_AMP_LOAD_DETECT_EN_SHIFT		6
+#define DA7218_HP_AMP_LOAD_DETECT_EN_MASK		(0x1 << 6)
+#define DA7218_HP_AMP_STEREO_DETECT_EN_SHIFT		7
+#define DA7218_HP_AMP_STEREO_DETECT_EN_MASK		(0x1 << 7)
+
+/* DA7218_HP_DIFF_CTRL = 0xD5 */
+#define DA7218_HP_AMP_DIFF_MODE_EN_SHIFT	0
+#define DA7218_HP_AMP_DIFF_MODE_EN_MASK		(0x1 << 0)
+#define DA7218_HP_AMP_SINGLE_SUPPLY_EN_SHIFT	4
+#define DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK	(0x1 << 4)
+
+/* DA7218_HP_DIFF_UNLOCK = 0xD7 */
+#define DA7218_HP_DIFF_UNLOCK_SHIFT	0
+#define DA7218_HP_DIFF_UNLOCK_MASK	(0x1 << 0)
+#define DA7218_HP_DIFF_UNLOCK_VAL	0xC3
+
+/* DA7218_HPLDET_JACK = 0xD8 */
+#define DA7218_HPLDET_JACK_RATE_SHIFT		0
+#define DA7218_HPLDET_JACK_RATE_MASK		(0x7 << 0)
+#define DA7218_HPLDET_JACK_DEBOUNCE_SHIFT	3
+#define DA7218_HPLDET_JACK_DEBOUNCE_MASK	(0x3 << 3)
+#define DA7218_HPLDET_JACK_THR_SHIFT		5
+#define DA7218_HPLDET_JACK_THR_MASK		(0x3 << 5)
+#define DA7218_HPLDET_JACK_EN_SHIFT		7
+#define DA7218_HPLDET_JACK_EN_MASK		(0x1 << 7)
+
+/* DA7218_HPLDET_CTRL = 0xD9 */
+#define DA7218_HPLDET_COMP_INV_SHIFT		0
+#define DA7218_HPLDET_COMP_INV_MASK		(0x1 << 0)
+#define DA7218_HPLDET_HYST_EN_SHIFT		1
+#define DA7218_HPLDET_HYST_EN_MASK		(0x1 << 1)
+#define DA7218_HPLDET_DISCHARGE_EN_SHIFT	7
+#define DA7218_HPLDET_DISCHARGE_EN_MASK		(0x1 << 7)
+
+/* DA7218_HPLDET_TEST = 0xDA */
+#define DA7218_HPLDET_COMP_STS_SHIFT	4
+#define DA7218_HPLDET_COMP_STS_MASK	(0x1 << 4)
+
+/* DA7218_REFERENCES = 0xDC */
+#define DA7218_BIAS_EN_SHIFT	3
+#define DA7218_BIAS_EN_MASK	(0x1 << 3)
+
+/* DA7218_IO_CTRL = 0xE0 */
+#define DA7218_IO_VOLTAGE_LEVEL_SHIFT		0
+#define DA7218_IO_VOLTAGE_LEVEL_MASK		(0x1 << 0)
+#define DA7218_IO_VOLTAGE_LEVEL_2_5V_3_6V	0
+#define DA7218_IO_VOLTAGE_LEVEL_1_5V_2_5V	1
+
+/* DA7218_LDO_CTRL = 0xE1 */
+#define DA7218_LDO_LEVEL_SELECT_SHIFT	4
+#define DA7218_LDO_LEVEL_SELECT_MASK	(0x3 << 4)
+#define DA7218_LDO_EN_SHIFT		7
+#define DA7218_LDO_EN_MASK		(0x1 << 7)
+
+/* DA7218_SIDETONE_CTRL = 0xE4 */
+#define DA7218_SIDETONE_MUTE_EN_SHIFT	6
+#define DA7218_SIDETONE_MUTE_EN_MASK	(0x1 << 6)
+#define DA7218_SIDETONE_FILTER_EN_SHIFT	7
+#define DA7218_SIDETONE_FILTER_EN_MASK	(0x1 << 7)
+
+/* DA7218_SIDETONE_IN_SELECT = 0xE5 */
+#define DA7218_SIDETONE_IN_SELECT_SHIFT	0
+#define DA7218_SIDETONE_IN_SELECT_MASK	(0x3 << 0)
+#define DA7218_SIDETONE_IN_SELECT_MAX	4
+
+/* DA7218_SIDETONE_GAIN = 0xE6 */
+#define DA7218_SIDETONE_GAIN_SHIFT	0
+#define DA7218_SIDETONE_GAIN_MASK	(0x1F << 0)
+
+/* DA7218_DROUTING_ST_OUTFILT_1L = 0xE8 */
+#define DA7218_OUTFILT_ST_1L_SRC_SHIFT	0
+#define DA7218_OUTFILT_ST_1L_SRC_MASK	(0x7 << 0)
+#define DA7218_DMIX_ST_SRC_OUTFILT1L	0
+#define DA7218_DMIX_ST_SRC_OUTFILT1R	1
+#define DA7218_DMIX_ST_SRC_SIDETONE	2
+
+/* DA7218_DROUTING_ST_OUTFILT_1R = 0xE9 */
+#define DA7218_OUTFILT_ST_1R_SRC_SHIFT	0
+#define DA7218_OUTFILT_ST_1R_SRC_MASK	(0x7 << 0)
+
+/* DA7218_SIDETONE_BIQ_3STAGE_DATA = 0xEA */
+#define DA7218_SIDETONE_BIQ_3STAGE_DATA_SHIFT	0
+#define DA7218_SIDETONE_BIQ_3STAGE_DATA_MASK	(0xFF << 0)
+
+/* DA7218_SIDETONE_BIQ_3STAGE_ADDR = 0xEB */
+#define DA7218_SIDETONE_BIQ_3STAGE_ADDR_SHIFT	0
+#define DA7218_SIDETONE_BIQ_3STAGE_ADDR_MASK	(0x1F << 0)
+#define DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE	30
+
+/* DA7218_EVENT_STATUS = 0xEC */
+#define DA7218_HPLDET_JACK_STS_SHIFT	7
+#define DA7218_HPLDET_JACK_STS_MASK	(0x1 << 7)
+
+/* DA7218_EVENT = 0xED */
+#define DA7218_LVL_DET_EVENT_SHIFT	0
+#define DA7218_LVL_DET_EVENT_MASK	(0x1 << 0)
+#define DA7218_HPLDET_JACK_EVENT_SHIFT	7
+#define DA7218_HPLDET_JACK_EVENT_MASK	(0x1 << 7)
+
+/* DA7218_EVENT_MASK	= 0xEE */
+#define DA7218_LVL_DET_EVENT_MSK_SHIFT		0
+#define DA7218_LVL_DET_EVENT_MSK_MASK		(0x1 << 0)
+#define DA7218_HPLDET_JACK_EVENT_IRQ_MSK_SHIFT	7
+#define DA7218_HPLDET_JACK_EVENT_IRQ_MSK_MASK	(0x1 << 7)
+
+/* DA7218_DMIC_1_CTRL = 0xF0 */
+#define DA7218_DMIC_1_DATA_SEL_SHIFT	0
+#define DA7218_DMIC_1_DATA_SEL_MASK	(0x1 << 0)
+#define DA7218_DMIC_1_SAMPLEPHASE_SHIFT	1
+#define DA7218_DMIC_1_SAMPLEPHASE_MASK	(0x1 << 1)
+#define DA7218_DMIC_1_CLK_RATE_SHIFT	2
+#define DA7218_DMIC_1_CLK_RATE_MASK	(0x1 << 2)
+#define DA7218_DMIC_1L_EN_SHIFT		6
+#define DA7218_DMIC_1L_EN_MASK		(0x1 << 6)
+#define DA7218_DMIC_1R_EN_SHIFT		7
+#define DA7218_DMIC_1R_EN_MASK		(0x1 << 7)
+
+/* DA7218_DMIC_2_CTRL = 0xF1 */
+#define DA7218_DMIC_2_DATA_SEL_SHIFT	0
+#define DA7218_DMIC_2_DATA_SEL_MASK	(0x1 << 0)
+#define DA7218_DMIC_2_SAMPLEPHASE_SHIFT	1
+#define DA7218_DMIC_2_SAMPLEPHASE_MASK	(0x1 << 1)
+#define DA7218_DMIC_2_CLK_RATE_SHIFT	2
+#define DA7218_DMIC_2_CLK_RATE_MASK	(0x1 << 2)
+#define DA7218_DMIC_2L_EN_SHIFT		6
+#define DA7218_DMIC_2L_EN_MASK		(0x1 << 6)
+#define DA7218_DMIC_2R_EN_SHIFT		7
+#define DA7218_DMIC_2R_EN_MASK		(0x1 << 7)
+
+/* DA7218_IN_1L_GAIN = 0xF4 */
+#define DA7218_IN_1L_DIGITAL_GAIN_SHIFT	0
+#define DA7218_IN_1L_DIGITAL_GAIN_MASK	(0x7F << 0)
+#define DA7218_IN_DIGITAL_GAIN_MAX	0x7F
+
+/* DA7218_IN_1R_GAIN = 0xF5 */
+#define DA7218_IN_1R_DIGITAL_GAIN_SHIFT	0
+#define DA7218_IN_1R_DIGITAL_GAIN_MASK	(0x7F << 0)
+
+/* DA7218_IN_2L_GAIN = 0xF6 */
+#define DA7218_IN_2L_DIGITAL_GAIN_SHIFT	0
+#define DA7218_IN_2L_DIGITAL_GAIN_MASK	(0x7F << 0)
+
+/* DA7218_IN_2R_GAIN = 0xF7 */
+#define DA7218_IN_2R_DIGITAL_GAIN_SHIFT	0
+#define DA7218_IN_2R_DIGITAL_GAIN_MASK	(0x7F << 0)
+
+/* DA7218_OUT_1L_GAIN = 0xF8 */
+#define DA7218_OUT_1L_DIGITAL_GAIN_SHIFT	0
+#define DA7218_OUT_1L_DIGITAL_GAIN_MASK		(0xFF << 0)
+#define DA7218_OUT_DIGITAL_GAIN_MIN		0x0
+#define DA7218_OUT_DIGITAL_GAIN_MAX		0x97
+
+/* DA7218_OUT_1R_GAIN = 0xF9 */
+#define DA7218_OUT_1R_DIGITAL_GAIN_SHIFT	0
+#define DA7218_OUT_1R_DIGITAL_GAIN_MASK		(0xFF << 0)
+
+/* DA7218_MICBIAS_CTRL = 0xFC */
+#define DA7218_MICBIAS_1_LEVEL_SHIFT	0
+#define DA7218_MICBIAS_1_LEVEL_MASK	(0x7 << 0)
+#define DA7218_MICBIAS_1_LP_MODE_SHIFT	3
+#define DA7218_MICBIAS_1_LP_MODE_MASK	(0x1 << 3)
+#define DA7218_MICBIAS_2_LEVEL_SHIFT	4
+#define DA7218_MICBIAS_2_LEVEL_MASK	(0x7 << 4)
+#define DA7218_MICBIAS_2_LP_MODE_SHIFT	7
+#define DA7218_MICBIAS_2_LP_MODE_MASK	(0x1 << 7)
+
+/* DA7218_MICBIAS_EN = 0xFD */
+#define DA7218_MICBIAS_1_EN_SHIFT	0
+#define DA7218_MICBIAS_1_EN_MASK	(0x1 << 0)
+#define DA7218_MICBIAS_2_EN_SHIFT	4
+#define DA7218_MICBIAS_2_EN_MASK	(0x1 << 4)
+
+
+/*
+ * General defines & data
+ */
+
+/* Register inversion */
+#define DA7218_NO_INVERT	0
+#define DA7218_INVERT		1
+
+/* Byte related defines */
+#define DA7218_BYTE_SHIFT	8
+#define DA7218_BYTE_MASK	0xFF
+#define DA7218_2BYTE_SHIFT	16
+#define DA7218_2BYTE_MASK	0xFFFF
+
+/* PLL Output Frequencies */
+#define DA7218_PLL_FREQ_OUT_90316	90316800
+#define DA7218_PLL_FREQ_OUT_98304	98304000
+
+/* ALC Calibration */
+#define DA7218_ALC_CALIB_DELAY_MIN	2500
+#define DA7218_ALC_CALIB_DELAY_MAX	5000
+#define DA7218_ALC_CALIB_MAX_TRIES	5
+
+/* Ref Oscillator */
+#define DA7218_REF_OSC_CHECK_DELAY_MIN	5000
+#define DA7218_REF_OSC_CHECK_DELAY_MAX	10000
+#define DA7218_REF_OSC_CHECK_TRIES	4
+
+/* SRM */
+#define DA7218_SRM_CHECK_DELAY		50
+#define DA7218_SRM_CHECK_TRIES		8
+
+/* Mic Level Detect */
+#define DA7218_MIC_LVL_DET_DELAY	50
+
+enum da7218_biq_cfg {
+	DA7218_BIQ_CFG_DATA = 0,
+	DA7218_BIQ_CFG_ADDR,
+	DA7218_BIQ_CFG_SIZE,
+};
+
+enum da7218_clk_src {
+	DA7218_CLKSRC_MCLK = 0,
+	DA7218_CLKSRC_MCLK_SQR,
+};
+
+enum da7218_sys_clk {
+	DA7218_SYSCLK_MCLK = 0,
+	DA7218_SYSCLK_PLL,
+	DA7218_SYSCLK_PLL_SRM,
+	DA7218_SYSCLK_PLL_32KHZ
+};
+
+enum da7218_dev_id {
+	DA7217_DEV_ID = 0,
+	DA7218_DEV_ID,
+};
+
+/* Regulators */
+enum da7218_supplies {
+	DA7218_SUPPLY_VDD = 0,
+	DA7218_SUPPLY_VDDMIC,
+	DA7218_SUPPLY_VDDIO,
+	DA7218_NUM_SUPPLIES,
+};
+
+/* Private data */
+struct da7218_priv {
+	struct da7218_pdata *pdata;
+
+	struct regulator_bulk_data supplies[DA7218_NUM_SUPPLIES];
+	struct regmap *regmap;
+	int dev_id;
+
+	struct snd_soc_jack *jack;
+	int irq;
+
+	struct clk *mclk;
+	unsigned int mclk_rate;
+
+	bool hp_single_supply;
+	bool master;
+	u8 alc_en;
+	u8 in_filt_en;
+	u8 mic_lvl_det_en;
+
+	u8 biq_5stage_coeff[DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE];
+	u8 stbiq_3stage_coeff[DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE];
+};
+
+/* HP detect control */
+int da7218_hpldet(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+
+#endif /* _DA7218_H */
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index f238c1e..81c0708 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -968,10 +968,11 @@
 	{"Mixin PGA", NULL, "Mic PGA"},
 	{"ADC", NULL, "Mixin PGA"},
 
-	{"Sidetone Filter", NULL, "ADC"},
 	{"Mixer In", NULL, "Mixer In Supply"},
 	{"Mixer In", "Mic Switch", "ADC"},
 
+	{"Sidetone Filter", NULL, "Mixer In"},
+
 	{"Tone Generator", NULL, "TONE"},
 
 	DA7219_OUT_DAI_MUX_ROUTES("Out DAIL Mux"),
@@ -1073,11 +1074,8 @@
 	u32 freq_ref;
 	u64 frac_div;
 
-	/* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */
-	if (da7219->mclk_rate == 32768) {
-		indiv_bits = DA7219_PLL_INDIV_2_5_MHZ;
-		indiv = DA7219_PLL_INDIV_2_5_MHZ_VAL;
-	} else if (da7219->mclk_rate < 2000000) {
+	/* Verify 2MHz - 54MHz MCLK provided, and set input divider */
+	if (da7219->mclk_rate < 2000000) {
 		dev_err(codec->dev, "PLL input clock %d below valid range\n",
 			da7219->mclk_rate);
 		return -EINVAL;
@@ -1118,9 +1116,6 @@
 	case DA7219_SYSCLK_PLL_SRM:
 		pll_ctrl |= DA7219_PLL_MODE_SRM;
 		break;
-	case DA7219_SYSCLK_PLL_32KHZ:
-		pll_ctrl |= DA7219_PLL_MODE_32KHZ;
-		break;
 	default:
 		dev_err(codec->dev, "Invalid PLL config\n");
 		return -EINVAL;
@@ -1161,18 +1156,44 @@
 		return -EINVAL;
 	}
 
-	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-	case SND_SOC_DAIFMT_NB_NF:
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_RIGHT_J:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			dai_clk_mode |= DA7219_DAI_WCLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			dai_clk_mode |= DA7219_DAI_CLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			dai_clk_mode |= DA7219_DAI_WCLK_POL_INV |
+					DA7219_DAI_CLK_POL_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
 		break;
-	case SND_SOC_DAIFMT_NB_IF:
-		dai_clk_mode |= DA7219_DAI_WCLK_POL_INV;
-		break;
-	case SND_SOC_DAIFMT_IB_NF:
-		dai_clk_mode |= DA7219_DAI_CLK_POL_INV;
-		break;
-	case SND_SOC_DAIFMT_IB_IF:
-		dai_clk_mode |= DA7219_DAI_WCLK_POL_INV |
-				DA7219_DAI_CLK_POL_INV;
+	case SND_SOC_DAIFMT_DSP_B:
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			dai_clk_mode |= DA7219_DAI_CLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			dai_clk_mode |= DA7219_DAI_WCLK_POL_INV |
+					DA7219_DAI_CLK_POL_INV;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			dai_clk_mode |= DA7219_DAI_WCLK_POL_INV;
+			break;
+		default:
+			return -EINVAL;
+		}
 		break;
 	default:
 		return -EINVAL;
@@ -1306,7 +1327,7 @@
 	}
 
 	channels = params_channels(params);
-	if ((channels < 1) | (channels > DA7219_DAI_CH_NUM_MAX)) {
+	if ((channels < 1) || (channels > DA7219_DAI_CH_NUM_MAX)) {
 		dev_err(codec->dev,
 			"Invalid number of channels, only 1 to %d supported\n",
 			DA7219_DAI_CH_NUM_MAX);
@@ -1405,28 +1426,12 @@
 };
 MODULE_DEVICE_TABLE(of, da7219_of_match);
 
-static enum da7219_ldo_lvl_sel da7219_of_ldo_lvl(struct snd_soc_codec *codec,
-						 u32 val)
-{
-	switch (val) {
-	case 1050:
-		return DA7219_LDO_LVL_SEL_1_05V;
-	case 1100:
-		return DA7219_LDO_LVL_SEL_1_10V;
-	case 1200:
-		return DA7219_LDO_LVL_SEL_1_20V;
-	case 1400:
-		return DA7219_LDO_LVL_SEL_1_40V;
-	default:
-		dev_warn(codec->dev, "Invalid LDO level");
-		return DA7219_LDO_LVL_SEL_1_05V;
-	}
-}
-
 static enum da7219_micbias_voltage
 	da7219_of_micbias_lvl(struct snd_soc_codec *codec, u32 val)
 {
 	switch (val) {
+	case 1600:
+		return DA7219_MICBIAS_1_6V;
 	case 1800:
 		return DA7219_MICBIAS_1_8V;
 	case 2000:
@@ -1469,9 +1474,6 @@
 	if (!pdata)
 		return NULL;
 
-	if (of_property_read_u32(np, "dlg,ldo-lvl", &of_val32) >= 0)
-		pdata->ldo_lvl_sel = da7219_of_ldo_lvl(codec, of_val32);
-
 	if (of_property_read_u32(np, "dlg,micbias-lvl", &of_val32) >= 0)
 		pdata->micbias_lvl = da7219_of_micbias_lvl(codec, of_val32);
 	else
@@ -1516,24 +1518,13 @@
 			snd_soc_update_bits(codec, DA7219_REFERENCES,
 					    DA7219_BIAS_EN_MASK,
 					    DA7219_BIAS_EN_MASK);
-
-			/* Enable Internal Digital LDO */
-			snd_soc_update_bits(codec, DA7219_LDO_CTRL,
-					    DA7219_LDO_EN_MASK,
-					    DA7219_LDO_EN_MASK);
 		}
 		break;
 	case SND_SOC_BIAS_OFF:
-		/* Only disable if jack detection not active */
-		if (!da7219->aad->jack) {
-			/* Bypass Internal Digital LDO */
-			snd_soc_update_bits(codec, DA7219_LDO_CTRL,
-					    DA7219_LDO_EN_MASK, 0);
-
-			/* Master bias */
+		/* Only disable master bias if jack detection not active */
+		if (!da7219->aad->jack)
 			snd_soc_update_bits(codec, DA7219_REFERENCES,
 					    DA7219_BIAS_EN_MASK, 0);
-		}
 
 		/* MCLK */
 		if (da7219->mclk)
@@ -1600,21 +1591,9 @@
 	if (pdata) {
 		u8 micbias_lvl = 0;
 
-		/* Internal LDO */
-		switch (pdata->ldo_lvl_sel) {
-		case DA7219_LDO_LVL_SEL_1_05V:
-		case DA7219_LDO_LVL_SEL_1_10V:
-		case DA7219_LDO_LVL_SEL_1_20V:
-		case DA7219_LDO_LVL_SEL_1_40V:
-			snd_soc_update_bits(codec, DA7219_LDO_CTRL,
-					    DA7219_LDO_LEVEL_SELECT_MASK,
-					    (pdata->ldo_lvl_sel <<
-					     DA7219_LDO_LEVEL_SELECT_SHIFT));
-			break;
-		}
-
 		/* Mic Bias voltages */
 		switch (pdata->micbias_lvl) {
+		case DA7219_MICBIAS_1_6V:
 		case DA7219_MICBIAS_1_8V:
 		case DA7219_MICBIAS_2_0V:
 		case DA7219_MICBIAS_2_2V:
@@ -1639,9 +1618,14 @@
 	}
 }
 
+static struct reg_sequence da7219_rev_aa_patch[] = {
+	{ DA7219_REFERENCES, 0x08 },
+};
+
 static int da7219_probe(struct snd_soc_codec *codec)
 {
 	struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+	unsigned int rev;
 	int ret;
 
 	mutex_init(&da7219->lock);
@@ -1651,6 +1635,26 @@
 	if (ret)
 		return ret;
 
+	ret = regmap_read(da7219->regmap, DA7219_CHIP_REVISION, &rev);
+	if (ret) {
+		dev_err(codec->dev, "Failed to read chip revision: %d\n", ret);
+		goto err_disable_reg;
+	}
+
+	switch (rev & DA7219_CHIP_MINOR_MASK) {
+	case 0:
+		ret = regmap_register_patch(da7219->regmap, da7219_rev_aa_patch,
+					    ARRAY_SIZE(da7219_rev_aa_patch));
+		if (ret) {
+			dev_err(codec->dev, "Failed to register AA patch: %d\n",
+				ret);
+			goto err_disable_reg;
+		}
+		break;
+	default:
+		break;
+	}
+
 	/* Handle DT/Platform data */
 	if (codec->dev->of_node)
 		da7219->pdata = da7219_of_to_pdata(codec);
@@ -1662,10 +1666,12 @@
 	/* Check if MCLK provided */
 	da7219->mclk = devm_clk_get(codec->dev, "mclk");
 	if (IS_ERR(da7219->mclk)) {
-		if (PTR_ERR(da7219->mclk) != -ENOENT)
-			return PTR_ERR(da7219->mclk);
-		else
+		if (PTR_ERR(da7219->mclk) != -ENOENT) {
+			ret = PTR_ERR(da7219->mclk);
+			goto err_disable_reg;
+		} else {
 			da7219->mclk = NULL;
+		}
 	}
 
 	/* Default PC counter to free-running */
@@ -1693,7 +1699,16 @@
 	snd_soc_write(codec, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK);
 
 	/* Initialise AAD block */
-	return da7219_aad_init(codec);
+	ret = da7219_aad_init(codec);
+	if (ret)
+		goto err_disable_reg;
+
+	return 0;
+
+err_disable_reg:
+	regulator_bulk_disable(DA7219_NUM_SUPPLIES, da7219->supplies);
+
+	return ret;
 }
 
 static int da7219_remove(struct snd_soc_codec *codec)
@@ -1776,7 +1791,7 @@
 	{ DA7219_DIG_ROUTING_DAC, 0x32 },
 	{ DA7219_DAI_OFFSET_LOWER, 0x00 },
 	{ DA7219_DAI_OFFSET_UPPER, 0x00 },
-	{ DA7219_REFERENCES, 0x00 },
+	{ DA7219_REFERENCES, 0x08 },
 	{ DA7219_MIXIN_L_SELECT, 0x00 },
 	{ DA7219_MIXIN_L_GAIN, 0x03 },
 	{ DA7219_ADC_L_GAIN, 0x6F },
@@ -1810,8 +1825,6 @@
 	{ DA7219_MIXOUT_R_CTRL, 0x10 },
 	{ DA7219_CHIP_ID1, 0x23 },
 	{ DA7219_CHIP_ID2, 0x93 },
-	{ DA7219_CHIP_REVISION, 0x00 },
-	{ DA7219_LDO_CTRL, 0x00 },
 	{ DA7219_IO_CTRL, 0x00 },
 	{ DA7219_GAIN_RAMP_CTRL, 0x00 },
 	{ DA7219_PC_COUNT, 0x02 },
diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h
index b514268..5a787e7 100644
--- a/sound/soc/codecs/da7219.h
+++ b/sound/soc/codecs/da7219.h
@@ -85,7 +85,6 @@
 #define DA7219_CHIP_ID1			0x81
 #define DA7219_CHIP_ID2			0x82
 #define DA7219_CHIP_REVISION		0x83
-#define DA7219_LDO_CTRL			0x90
 #define DA7219_IO_CTRL			0x91
 #define DA7219_GAIN_RAMP_CTRL		0x92
 #define DA7219_PC_COUNT			0x94
@@ -207,7 +206,6 @@
 #define DA7219_PLL_MODE_BYPASS		(0x0 << 6)
 #define DA7219_PLL_MODE_NORMAL		(0x1 << 6)
 #define DA7219_PLL_MODE_SRM		(0x2 << 6)
-#define DA7219_PLL_MODE_32KHZ		(0x3 << 6)
 
 /* DA7219_PLL_FRAC_TOP = 0x22 */
 #define DA7219_PLL_FBDIV_FRAC_TOP_SHIFT	0
@@ -569,12 +567,6 @@
 #define DA7219_CHIP_MAJOR_SHIFT	4
 #define DA7219_CHIP_MAJOR_MASK	(0xF << 4)
 
-/* DA7219_LDO_CTRL = 0x90 */
-#define DA7219_LDO_LEVEL_SELECT_SHIFT	4
-#define DA7219_LDO_LEVEL_SELECT_MASK	(0x3 << 4)
-#define DA7219_LDO_EN_SHIFT		7
-#define DA7219_LDO_EN_MASK		(0x1 << 7)
-
 /* DA7219_IO_CTRL = 0x91 */
 #define DA7219_IO_VOLTAGE_LEVEL_SHIFT		0
 #define DA7219_IO_VOLTAGE_LEVEL_MASK		(0x1 << 0)
@@ -787,7 +779,6 @@
 	DA7219_SYSCLK_MCLK = 0,
 	DA7219_SYSCLK_PLL,
 	DA7219_SYSCLK_PLL_SRM,
-	DA7219_SYSCLK_PLL_32KHZ
 };
 
 /* Regulators */
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
new file mode 100644
index 0000000..5a1ec0f
--- /dev/null
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -0,0 +1,697 @@
+/*
+ *  hdac_hdmi.c - ASoc HDA-HDMI codec driver for Intel platforms
+ *
+ *  Copyright (C) 2014-2015 Intel Corp
+ *  Author: Samreen Nilofer <samreen.nilofer@intel.com>
+ *	    Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/hdmi.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/hdaudio_ext.h>
+#include <sound/hda_i915.h>
+#include "../../hda/local.h"
+
+#define AMP_OUT_MUTE		0xb080
+#define AMP_OUT_UNMUTE		0xb000
+#define PIN_OUT			(AC_PINCTL_OUT_EN)
+
+#define HDA_MAX_CONNECTIONS     32
+
+struct hdac_hdmi_cvt_params {
+	unsigned int channels_min;
+	unsigned int channels_max;
+	u32 rates;
+	u64 formats;
+	unsigned int maxbps;
+};
+
+struct hdac_hdmi_cvt {
+	struct list_head head;
+	hda_nid_t nid;
+	struct hdac_hdmi_cvt_params params;
+};
+
+struct hdac_hdmi_pin {
+	struct list_head head;
+	hda_nid_t nid;
+	int num_mux_nids;
+	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
+};
+
+struct hdac_hdmi_dai_pin_map {
+	int dai_id;
+	struct hdac_hdmi_pin *pin;
+	struct hdac_hdmi_cvt *cvt;
+};
+
+struct hdac_hdmi_priv {
+	struct hdac_hdmi_dai_pin_map dai_map[3];
+	struct list_head pin_list;
+	struct list_head cvt_list;
+	int num_pin;
+	int num_cvt;
+};
+
+static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
+{
+	struct hdac_device *hdac = dev_to_hdac_dev(dev);
+
+	return to_ehdac_device(hdac);
+}
+
+static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac,
+				hda_nid_t cvt_nid, hda_nid_t pin_nid,
+				u32 stream_tag, int format)
+{
+	unsigned int val;
+
+	dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n",
+			cvt_nid, pin_nid, stream_tag, format);
+
+	val = (stream_tag << 4);
+
+	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
+				AC_VERB_SET_CHANNEL_STREAMID, val);
+	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
+				AC_VERB_SET_STREAM_FORMAT, format);
+
+	return 0;
+}
+
+static void
+hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid,
+				int packet_index, int byte_index)
+{
+	int val;
+
+	val = (packet_index << 5) | (byte_index & 0x1f);
+
+	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+				AC_VERB_SET_HDMI_DIP_INDEX, val);
+}
+
+static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
+				hda_nid_t cvt_nid, hda_nid_t pin_nid)
+{
+	uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
+	struct hdmi_audio_infoframe frame;
+	u8 *dip = (u8 *)&frame;
+	int ret;
+	int i;
+
+	hdmi_audio_infoframe_init(&frame);
+
+	/* Default stereo for now */
+	frame.channels = 2;
+
+	/* setup channel count */
+	snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
+			    AC_VERB_SET_CVT_CHAN_COUNT, frame.channels - 1);
+
+	ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
+	if (ret < 0)
+		return ret;
+
+	/* stop infoframe transmission */
+	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
+	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
+
+
+	/*  Fill infoframe. Index auto-incremented */
+	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
+	for (i = 0; i < sizeof(frame); i++)
+		snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+				AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
+
+	/* Start infoframe */
+	hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
+	snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+			AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
+
+	return 0;
+}
+
+static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
+		struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state)
+{
+	/* Power up pin widget */
+	if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid,
+						pwr_state))
+		snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0,
+			AC_VERB_SET_POWER_STATE, pwr_state);
+
+	/* Power up converter */
+	if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid,
+						pwr_state))
+		snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
+			AC_VERB_SET_POWER_STATE, pwr_state);
+}
+
+static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
+	struct hdac_hdmi_priv *hdmi = hdac->private_data;
+	struct hdac_hdmi_dai_pin_map *dai_map;
+	struct hdac_ext_dma_params *dd;
+	int ret;
+
+	if (dai->id > 0) {
+		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
+		return -ENODEV;
+	}
+
+	dai_map = &hdmi->dai_map[dai->id];
+
+	dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
+	dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
+			dd->stream_tag,	dd->format);
+
+	ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid,
+						dai_map->pin->nid);
+	if (ret < 0)
+		return ret;
+
+	return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid,
+			dai_map->pin->nid, dd->stream_tag, dd->format);
+}
+
+static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
+{
+	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
+	struct hdac_ext_dma_params *dd;
+
+	if (dai->id > 0) {
+		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
+		return -ENODEV;
+	}
+
+	dd = kzalloc(sizeof(*dd), GFP_KERNEL);
+	if (!dd)
+		return -ENOMEM;
+	dd->format = snd_hdac_calc_stream_format(params_rate(hparams),
+			params_channels(hparams), params_format(hparams),
+			24, 0);
+
+	snd_soc_dai_set_dma_data(dai, substream, (void *)dd);
+
+	return 0;
+}
+
+static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
+	struct hdac_ext_dma_params *dd;
+	struct hdac_hdmi_priv *hdmi = edev->private_data;
+	struct hdac_hdmi_dai_pin_map *dai_map;
+
+	dai_map = &hdmi->dai_map[dai->id];
+
+	snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
+				AC_VERB_SET_CHANNEL_STREAMID, 0);
+	snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
+				AC_VERB_SET_STREAM_FORMAT, 0);
+
+	dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
+	snd_soc_dai_set_dma_data(dai, substream, NULL);
+
+	kfree(dd);
+
+	return 0;
+}
+
+static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
+	struct hdac_hdmi_priv *hdmi = hdac->private_data;
+	struct hdac_hdmi_dai_pin_map *dai_map;
+	int val;
+
+	if (dai->id > 0) {
+		dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
+		return -ENODEV;
+	}
+
+	dai_map = &hdmi->dai_map[dai->id];
+
+	val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin->nid, 0,
+					AC_VERB_GET_PIN_SENSE, 0);
+	dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val);
+
+	if ((!(val & AC_PINSENSE_PRESENCE)) || (!(val & AC_PINSENSE_ELDV))) {
+		dev_err(&hdac->hdac.dev, "Monitor presence invalid with val: %x\n", val);
+		return -ENODEV;
+	}
+
+	hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
+
+	snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
+			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+
+	snd_pcm_hw_constraint_step(substream->runtime, 0,
+				   SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+
+	return 0;
+}
+
+static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
+	struct hdac_hdmi_priv *hdmi = hdac->private_data;
+	struct hdac_hdmi_dai_pin_map *dai_map;
+
+	dai_map = &hdmi->dai_map[dai->id];
+
+	hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
+
+	snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
+			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+}
+
+static int
+hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
+{
+	int err;
+
+	/* Only stereo supported as of now */
+	cvt->params.channels_min = cvt->params.channels_max = 2;
+
+	err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
+			&cvt->params.rates,
+			&cvt->params.formats,
+			&cvt->params.maxbps);
+	if (err < 0)
+		dev_err(&hdac->dev,
+			"Failed to query pcm params for nid %d: %d\n",
+			cvt->nid, err);
+
+	return err;
+}
+
+static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w,
+				enum snd_soc_dapm_type id,
+				const char *wname, const char *stream)
+{
+	w->id = id;
+	w->name = wname;
+	w->sname = stream;
+	w->reg = SND_SOC_NOPM;
+	w->shift = 0;
+	w->kcontrol_news = NULL;
+	w->num_kcontrols = 0;
+	w->priv = NULL;
+}
+
+static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
+		const char *sink, const char *control, const char *src)
+{
+	route->sink = sink;
+	route->source = src;
+	route->control = control;
+	route->connected = NULL;
+}
+
+static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm,
+					struct hdac_hdmi_dai_pin_map *dai_map)
+{
+	struct snd_soc_dapm_route route[1];
+	struct snd_soc_dapm_widget widgets[2] = { {0} };
+
+	memset(&route, 0, sizeof(route));
+
+	hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output,
+			"hif1 Output", NULL);
+	hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in,
+			"Coverter 1", "hif1");
+
+	hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1");
+
+	snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets));
+	snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route));
+}
+
+static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
+{
+	struct hdac_hdmi_priv *hdmi = edev->private_data;
+	struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0];
+	struct hdac_hdmi_cvt *cvt;
+	struct hdac_hdmi_pin *pin;
+
+	if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
+		return -EINVAL;
+
+	/*
+	 * Currently on board only 1 pin and 1 converter is enabled for
+	 * simplification, more will be added eventually
+	 * So using fixed map for dai_id:pin:cvt
+	 */
+	cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head);
+	pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head);
+
+	dai_map->dai_id = 0;
+	dai_map->pin = pin;
+
+	dai_map->cvt = cvt;
+
+	/* Enable out path for this pin widget */
+	snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
+			AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+	/* Enable transmission */
+	snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+			AC_VERB_SET_DIGI_CONVERT_1, 1);
+
+	/* Category Code (CC) to zero */
+	snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+			AC_VERB_SET_DIGI_CONVERT_2, 0);
+
+	snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
+			AC_VERB_SET_CONNECT_SEL, 0);
+
+	return 0;
+}
+
+static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
+{
+	struct hdac_hdmi_priv *hdmi = edev->private_data;
+	struct hdac_hdmi_cvt *cvt;
+
+	cvt = kzalloc(sizeof(*cvt), GFP_KERNEL);
+	if (!cvt)
+		return -ENOMEM;
+
+	cvt->nid = nid;
+
+	list_add_tail(&cvt->head, &hdmi->cvt_list);
+	hdmi->num_cvt++;
+
+	return hdac_hdmi_query_cvt_params(&edev->hdac, cvt);
+}
+
+static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
+{
+	struct hdac_hdmi_priv *hdmi = edev->private_data;
+	struct hdac_hdmi_pin *pin;
+
+	pin = kzalloc(sizeof(*pin), GFP_KERNEL);
+	if (!pin)
+		return -ENOMEM;
+
+	pin->nid = nid;
+
+	list_add_tail(&pin->head, &hdmi->pin_list);
+	hdmi->num_pin++;
+
+	return 0;
+}
+
+/*
+ * Parse all nodes and store the cvt/pin nids in array
+ * Add one time initialization for pin and cvt widgets
+ */
+static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
+{
+	hda_nid_t nid;
+	int i, num_nodes;
+	struct hdac_device *hdac = &edev->hdac;
+	struct hdac_hdmi_priv *hdmi = edev->private_data;
+	int ret;
+
+	num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
+	if (!nid || num_nodes <= 0) {
+		dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n");
+		return -EINVAL;
+	}
+
+	hdac->num_nodes = num_nodes;
+	hdac->start_nid = nid;
+
+	for (i = 0; i < hdac->num_nodes; i++, nid++) {
+		unsigned int caps;
+		unsigned int type;
+
+		caps = get_wcaps(hdac, nid);
+		type = get_wcaps_type(caps);
+
+		if (!(caps & AC_WCAP_DIGITAL))
+			continue;
+
+		switch (type) {
+
+		case AC_WID_AUD_OUT:
+			ret = hdac_hdmi_add_cvt(edev, nid);
+			if (ret < 0)
+				return ret;
+			break;
+
+		case AC_WID_PIN:
+			ret = hdac_hdmi_add_pin(edev, nid);
+			if (ret < 0)
+				return ret;
+			break;
+		}
+	}
+
+	hdac->end_nid = nid;
+
+	if (!hdmi->num_pin || !hdmi->num_cvt)
+		return -EIO;
+
+	return hdac_hdmi_init_dai_map(edev);
+}
+
+static int hdmi_codec_probe(struct snd_soc_codec *codec)
+{
+	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+	struct hdac_hdmi_priv *hdmi = edev->private_data;
+	struct snd_soc_dapm_context *dapm =
+		snd_soc_component_get_dapm(&codec->component);
+
+	edev->scodec = codec;
+
+	create_fill_widget_route_map(dapm, &hdmi->dai_map[0]);
+
+	/* Imp: Store the card pointer in hda_codec */
+	edev->card = dapm->card->snd_card;
+
+	/*
+	 * hdac_device core already sets the state to active and calls
+	 * get_noresume. So enable runtime and set the device to suspend.
+	 */
+	pm_runtime_enable(&edev->hdac.dev);
+	pm_runtime_put(&edev->hdac.dev);
+	pm_runtime_suspend(&edev->hdac.dev);
+
+	return 0;
+}
+
+static int hdmi_codec_remove(struct snd_soc_codec *codec)
+{
+	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+
+	pm_runtime_disable(&edev->hdac.dev);
+	return 0;
+}
+
+static struct snd_soc_codec_driver hdmi_hda_codec = {
+	.probe		= hdmi_codec_probe,
+	.remove		= hdmi_codec_remove,
+	.idle_bias_off	= true,
+};
+
+static struct snd_soc_dai_ops hdmi_dai_ops = {
+	.startup = hdac_hdmi_pcm_open,
+	.shutdown = hdac_hdmi_pcm_close,
+	.hw_params = hdac_hdmi_set_hw_params,
+	.prepare = hdac_hdmi_playback_prepare,
+	.hw_free = hdac_hdmi_playback_cleanup,
+};
+
+static struct snd_soc_dai_driver hdmi_dais[] = {
+	{	.name = "intel-hdmi-hif1",
+		.playback = {
+			.stream_name = "hif1",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_32000 |
+				SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+				SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S20_3LE |
+				SNDRV_PCM_FMTBIT_S24_LE |
+				SNDRV_PCM_FMTBIT_S32_LE,
+
+		},
+		.ops = &hdmi_dai_ops,
+	},
+};
+
+static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
+{
+	struct hdac_device *codec = &edev->hdac;
+	struct hdac_hdmi_priv *hdmi_priv;
+	int ret = 0;
+
+	hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
+	if (hdmi_priv == NULL)
+		return -ENOMEM;
+
+	edev->private_data = hdmi_priv;
+
+	dev_set_drvdata(&codec->dev, edev);
+
+	INIT_LIST_HEAD(&hdmi_priv->pin_list);
+	INIT_LIST_HEAD(&hdmi_priv->cvt_list);
+
+	ret = hdac_hdmi_parse_and_map_nid(edev);
+	if (ret < 0)
+		return ret;
+
+	/* ASoC specific initialization */
+	return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
+			hdmi_dais, ARRAY_SIZE(hdmi_dais));
+}
+
+static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
+{
+	struct hdac_hdmi_priv *hdmi = edev->private_data;
+	struct hdac_hdmi_pin *pin, *pin_next;
+	struct hdac_hdmi_cvt *cvt, *cvt_next;
+
+	snd_soc_unregister_codec(&edev->hdac.dev);
+
+	list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) {
+		list_del(&cvt->head);
+		kfree(cvt);
+	}
+
+	list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) {
+		list_del(&pin->head);
+		kfree(pin);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int hdac_hdmi_runtime_suspend(struct device *dev)
+{
+	struct hdac_ext_device *edev = to_hda_ext_device(dev);
+	struct hdac_device *hdac = &edev->hdac;
+	struct hdac_bus *bus = hdac->bus;
+	int err;
+
+	dev_dbg(dev, "Enter: %s\n", __func__);
+
+	/* controller may not have been initialized for the first time */
+	if (!bus)
+		return 0;
+
+	/* Power down afg */
+	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3))
+		snd_hdac_codec_write(hdac, hdac->afg, 0,
+			AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+
+	err = snd_hdac_display_power(bus, false);
+	if (err < 0) {
+		dev_err(bus->dev, "Cannot turn on display power on i915\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int hdac_hdmi_runtime_resume(struct device *dev)
+{
+	struct hdac_ext_device *edev = to_hda_ext_device(dev);
+	struct hdac_device *hdac = &edev->hdac;
+	struct hdac_bus *bus = hdac->bus;
+	int err;
+
+	dev_dbg(dev, "Enter: %s\n", __func__);
+
+	/* controller may not have been initialized for the first time */
+	if (!bus)
+		return 0;
+
+	err = snd_hdac_display_power(bus, true);
+	if (err < 0) {
+		dev_err(bus->dev, "Cannot turn on display power on i915\n");
+		return err;
+	}
+
+	/* Power up afg */
+	if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0))
+		snd_hdac_codec_write(hdac, hdac->afg, 0,
+			AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+	return 0;
+}
+#else
+#define hdac_hdmi_runtime_suspend NULL
+#define hdac_hdmi_runtime_resume NULL
+#endif
+
+static const struct dev_pm_ops hdac_hdmi_pm = {
+	SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
+};
+
+static const struct hda_device_id hdmi_list[] = {
+	HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
+	{}
+};
+
+MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
+
+static struct hdac_ext_driver hdmi_driver = {
+	. hdac = {
+		.driver = {
+			.name   = "HDMI HDA Codec",
+			.pm = &hdac_hdmi_pm,
+		},
+		.id_table       = hdmi_list,
+	},
+	.probe          = hdac_hdmi_dev_probe,
+	.remove         = hdac_hdmi_dev_remove,
+};
+
+static int __init hdmi_init(void)
+{
+	return snd_hda_ext_driver_register(&hdmi_driver);
+}
+
+static void __exit hdmi_exit(void)
+{
+	snd_hda_ext_driver_unregister(&hdmi_driver);
+}
+
+module_init(hdmi_init);
+module_exit(hdmi_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("HDMI HD codec");
+MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>");
+MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>");
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
new file mode 100644
index 0000000..9b6e884
--- /dev/null
+++ b/sound/soc/codecs/inno_rk3036.c
@@ -0,0 +1,490 @@
+/*
+ * Driver of Inno codec for rk3036 by Rockchip Inc.
+ *
+ * Author: Rockchip Inc.
+ * Author: Zheng ShunQian<zhengsq@rock-chips.com>
+ */
+
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-dai.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/io.h>
+
+#include "inno_rk3036.h"
+
+struct rk3036_codec_priv {
+	void __iomem *base;
+	struct clk *pclk;
+	struct regmap *regmap;
+	struct device *dev;
+};
+
+static const DECLARE_TLV_DB_MINMAX(rk3036_codec_hp_tlv, -39, 0);
+
+static int rk3036_codec_antipop_info(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+
+	return 0;
+}
+
+static int rk3036_codec_antipop_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	int val, ret, regval;
+
+	ret = snd_soc_component_read(component, INNO_R09, &regval);
+	if (ret)
+		return ret;
+	val = ((regval >> INNO_R09_HPL_ANITPOP_SHIFT) &
+	       INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON;
+	ucontrol->value.integer.value[0] = val;
+
+	val = ((regval >> INNO_R09_HPR_ANITPOP_SHIFT) &
+	       INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON;
+	ucontrol->value.integer.value[1] = val;
+
+	return 0;
+}
+
+static int rk3036_codec_antipop_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	int val, ret, regmsk;
+
+	val = (ucontrol->value.integer.value[0] ?
+	       INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) <<
+	      INNO_R09_HPL_ANITPOP_SHIFT;
+	val |= (ucontrol->value.integer.value[1] ?
+		INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) <<
+	       INNO_R09_HPR_ANITPOP_SHIFT;
+
+	regmsk = INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPL_ANITPOP_SHIFT |
+		 INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPR_ANITPOP_SHIFT;
+
+	ret = snd_soc_component_update_bits(component, INNO_R09,
+					    regmsk, val);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+#define SOC_RK3036_CODEC_ANTIPOP_DECL(xname) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = rk3036_codec_antipop_info, .get = rk3036_codec_antipop_get, \
+	.put = rk3036_codec_antipop_put, }
+
+static const struct snd_kcontrol_new rk3036_codec_dapm_controls[] = {
+	SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", INNO_R07, INNO_R08,
+		INNO_HP_GAIN_SHIFT, INNO_HP_GAIN_N39DB,
+		INNO_HP_GAIN_0DB, 0, rk3036_codec_hp_tlv),
+	SOC_DOUBLE("Zero Cross Switch", INNO_R06, INNO_R06_VOUTL_CZ_SHIFT,
+		INNO_R06_VOUTR_CZ_SHIFT, 1, 0),
+	SOC_DOUBLE("Headphone Switch", INNO_R09, INNO_R09_HPL_MUTE_SHIFT,
+		INNO_R09_HPR_MUTE_SHIFT, 1, 0),
+	SOC_RK3036_CODEC_ANTIPOP_DECL("Anti-pop Switch"),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpl_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Left Out Switch", INNO_R09,
+			INNO_R09_DACL_SWITCH_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpr_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Right Out Switch", INNO_R09,
+			INNO_R09_DACR_SWITCH_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpl_switch_controls[] = {
+	SOC_DAPM_SINGLE("HP Left Out Switch", INNO_R05,
+			INNO_R05_HPL_WORK_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpr_switch_controls[] = {
+	SOC_DAPM_SINGLE("HP Right Out Switch", INNO_R05,
+			INNO_R05_HPR_WORK_SHIFT, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget rk3036_codec_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY_S("DAC PWR", 1, INNO_R06,
+			      INNO_R06_DAC_EN_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DACL VREF", 2, INNO_R04,
+			      INNO_R04_DACL_VREF_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DACR VREF", 2, INNO_R04,
+			      INNO_R04_DACR_VREF_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DACL HiLo VREF", 3, INNO_R06,
+			      INNO_R06_DACL_HILO_VREF_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DACR HiLo VREF", 3, INNO_R06,
+			      INNO_R06_DACR_HILO_VREF_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DACR CLK", 3, INNO_R04,
+			      INNO_R04_DACR_CLK_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DACL CLK", 3, INNO_R04,
+			      INNO_R04_DACL_CLK_SHIFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_DAC("DACL", "Left Playback", INNO_R04,
+			 INNO_R04_DACL_SW_SHIFT, 0),
+	SND_SOC_DAPM_DAC("DACR", "Right Playback", INNO_R04,
+			 INNO_R04_DACR_SW_SHIFT, 0),
+
+	SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0,
+		rk3036_codec_hpl_mixer_controls,
+		ARRAY_SIZE(rk3036_codec_hpl_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0,
+		rk3036_codec_hpr_mixer_controls,
+		ARRAY_SIZE(rk3036_codec_hpr_mixer_controls)),
+
+	SND_SOC_DAPM_PGA("HP Left Out", INNO_R05,
+			 INNO_R05_HPL_EN_SHIFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HP Right Out", INNO_R05,
+			 INNO_R05_HPR_EN_SHIFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("HP Left Switch",  SND_SOC_NOPM, 0, 0,
+			   rk3036_codec_hpl_switch_controls,
+			   ARRAY_SIZE(rk3036_codec_hpl_switch_controls)),
+	SND_SOC_DAPM_MIXER("HP Right Switch",  SND_SOC_NOPM, 0, 0,
+			   rk3036_codec_hpr_switch_controls,
+			   ARRAY_SIZE(rk3036_codec_hpr_switch_controls)),
+
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+static const struct snd_soc_dapm_route rk3036_codec_dapm_routes[] = {
+	{"DACL VREF", NULL, "DAC PWR"},
+	{"DACR VREF", NULL, "DAC PWR"},
+	{"DACL HiLo VREF", NULL, "DAC PWR"},
+	{"DACR HiLo VREF", NULL, "DAC PWR"},
+	{"DACL CLK", NULL, "DAC PWR"},
+	{"DACR CLK", NULL, "DAC PWR"},
+
+	{"DACL", NULL, "DACL VREF"},
+	{"DACL", NULL, "DACL HiLo VREF"},
+	{"DACL", NULL, "DACL CLK"},
+	{"DACR", NULL, "DACR VREF"},
+	{"DACR", NULL, "DACR HiLo VREF"},
+	{"DACR", NULL, "DACR CLK"},
+
+	{"Left Headphone Mixer", "DAC Left Out Switch", "DACL"},
+	{"Right Headphone Mixer", "DAC Right Out Switch", "DACR"},
+	{"HP Left Out", NULL, "Left Headphone Mixer"},
+	{"HP Right Out", NULL, "Right Headphone Mixer"},
+
+	{"HP Left Switch", "HP Left Out Switch", "HP Left Out"},
+	{"HP Right Switch", "HP Right Out Switch", "HP Right Out"},
+
+	{"HPL", NULL, "HP Left Switch"},
+	{"HPR", NULL, "HP Right Switch"},
+};
+
+static int rk3036_codec_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned int reg01_val = 0,  reg02_val = 0, reg03_val = 0;
+
+	dev_dbg(codec->dev, "rk3036_codec dai set fmt : %08x\n", fmt);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg01_val |= INNO_R01_PINDIR_IN_SLAVE |
+			     INNO_R01_I2SMODE_SLAVE;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		reg01_val |= INNO_R01_PINDIR_OUT_MASTER |
+			     INNO_R01_I2SMODE_MASTER;
+		break;
+	default:
+		dev_err(codec->dev, "invalid fmt\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		reg02_val |= INNO_R02_DACM_PCM;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		reg02_val |= INNO_R02_DACM_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		reg02_val |= INNO_R02_DACM_RJM;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		reg02_val |= INNO_R02_DACM_LJM;
+		break;
+	default:
+		dev_err(codec->dev, "set dai format failed\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		reg02_val |= INNO_R02_LRCP_NORMAL;
+		reg03_val |= INNO_R03_BCP_NORMAL;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		reg02_val |= INNO_R02_LRCP_REVERSAL;
+		reg03_val |= INNO_R03_BCP_REVERSAL;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		reg02_val |= INNO_R02_LRCP_REVERSAL;
+		reg03_val |= INNO_R03_BCP_NORMAL;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		reg02_val |= INNO_R02_LRCP_NORMAL;
+		reg03_val |= INNO_R03_BCP_REVERSAL;
+		break;
+	default:
+		dev_err(codec->dev, "set dai format failed\n");
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, INNO_R01, INNO_R01_I2SMODE_MSK |
+			    INNO_R01_PINDIR_MSK, reg01_val);
+	snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK |
+			    INNO_R02_DACM_MSK, reg02_val);
+	snd_soc_update_bits(codec, INNO_R03, INNO_R03_BCP_MSK, reg03_val);
+
+	return 0;
+}
+
+static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream,
+				      struct snd_pcm_hw_params *hw_params,
+				      struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned int reg02_val = 0, reg03_val = 0;
+
+	switch (params_format(hw_params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		reg02_val |= INNO_R02_VWL_16BIT;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		reg02_val |= INNO_R02_VWL_20BIT;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		reg02_val |= INNO_R02_VWL_24BIT;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		reg02_val |= INNO_R02_VWL_32BIT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	reg02_val |= INNO_R02_LRCP_NORMAL;
+	reg03_val |= INNO_R03_FWL_32BIT | INNO_R03_DACR_WORK;
+
+	snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK |
+			    INNO_R02_VWL_MSK, reg02_val);
+	snd_soc_update_bits(codec, INNO_R03, INNO_R03_DACR_MSK |
+			    INNO_R03_FWL_MSK, reg03_val);
+	return 0;
+}
+
+#define RK3036_CODEC_RATES (SNDRV_PCM_RATE_8000  | \
+			    SNDRV_PCM_RATE_16000 | \
+			    SNDRV_PCM_RATE_32000 | \
+			    SNDRV_PCM_RATE_44100 | \
+			    SNDRV_PCM_RATE_48000 | \
+			    SNDRV_PCM_RATE_96000)
+
+#define RK3036_CODEC_FMTS (SNDRV_PCM_FMTBIT_S16_LE  | \
+			   SNDRV_PCM_FMTBIT_S20_3LE | \
+			   SNDRV_PCM_FMTBIT_S24_LE  | \
+			   SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops rk3036_codec_dai_ops = {
+	.set_fmt	= rk3036_codec_dai_set_fmt,
+	.hw_params	= rk3036_codec_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver rk3036_codec_dai_driver[] = {
+	{
+		.name = "rk3036-codec-dai",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RK3036_CODEC_RATES,
+			.formats = RK3036_CODEC_FMTS,
+		},
+		.ops = &rk3036_codec_dai_ops,
+		.symmetric_rates = 1,
+	},
+};
+
+static void rk3036_codec_reset(struct snd_soc_codec *codec)
+{
+	snd_soc_write(codec, INNO_R00,
+		      INNO_R00_CSR_RESET | INNO_R00_CDCR_RESET);
+	snd_soc_write(codec, INNO_R00,
+		      INNO_R00_CSR_WORK | INNO_R00_CDCR_WORK);
+}
+
+static int rk3036_codec_probe(struct snd_soc_codec *codec)
+{
+	rk3036_codec_reset(codec);
+	return 0;
+}
+
+static int rk3036_codec_remove(struct snd_soc_codec *codec)
+{
+	rk3036_codec_reset(codec);
+	return 0;
+}
+
+static int rk3036_codec_set_bias_level(struct snd_soc_codec *codec,
+				       enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_STANDBY:
+		/* set a big current for capacitor charging. */
+		snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR);
+		/* start precharge */
+		snd_soc_write(codec, INNO_R06, INNO_R06_DAC_PRECHARGE);
+
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		/* set a big current for capacitor discharging. */
+		snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR);
+		/* start discharge. */
+		snd_soc_write(codec, INNO_R06, INNO_R06_DAC_DISCHARGE);
+
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver rk3036_codec_driver = {
+	.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),
+};
+
+static const struct regmap_config rk3036_codec_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+};
+
+#define GRF_SOC_CON0		0x00140
+#define GRF_ACODEC_SEL		(BIT(10) | BIT(16 + 10))
+
+static int rk3036_codec_platform_probe(struct platform_device *pdev)
+{
+	struct rk3036_codec_priv *priv;
+	struct device_node *of_node = pdev->dev.of_node;
+	struct resource *res;
+	void __iomem *base;
+	struct regmap *grf;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	priv->base = base;
+	priv->regmap = devm_regmap_init_mmio(&pdev->dev, priv->base,
+					     &rk3036_codec_regmap_config);
+	if (IS_ERR(priv->regmap)) {
+		dev_err(&pdev->dev, "init regmap failed\n");
+		return PTR_ERR(priv->regmap);
+	}
+
+	grf = syscon_regmap_lookup_by_phandle(of_node, "rockchip,grf");
+	if (IS_ERR(grf)) {
+		dev_err(&pdev->dev, "needs 'rockchip,grf' property\n");
+		return PTR_ERR(grf);
+	}
+	ret = regmap_write(grf, GRF_SOC_CON0, GRF_ACODEC_SEL);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not write to GRF: %d\n", ret);
+		return ret;
+	}
+
+	priv->pclk = devm_clk_get(&pdev->dev, "acodec_pclk");
+	if (IS_ERR(priv->pclk))
+		return PTR_ERR(priv->pclk);
+
+	ret = clk_prepare_enable(priv->pclk);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to enable clk\n");
+		return ret;
+	}
+
+	priv->dev = &pdev->dev;
+	dev_set_drvdata(&pdev->dev, priv);
+
+	ret = snd_soc_register_codec(&pdev->dev, &rk3036_codec_driver,
+				     rk3036_codec_dai_driver,
+				     ARRAY_SIZE(rk3036_codec_dai_driver));
+	if (ret) {
+		clk_disable_unprepare(priv->pclk);
+		dev_set_drvdata(&pdev->dev, NULL);
+	}
+
+	return ret;
+}
+
+static int rk3036_codec_platform_remove(struct platform_device *pdev)
+{
+	struct rk3036_codec_priv *priv = dev_get_drvdata(&pdev->dev);
+
+	snd_soc_unregister_codec(&pdev->dev);
+	clk_disable_unprepare(priv->pclk);
+
+	return 0;
+}
+
+static const struct of_device_id rk3036_codec_of_match[] = {
+	{ .compatible = "rockchip,rk3036-codec", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, rk3036_codec_of_match);
+
+static struct platform_driver rk3036_codec_platform_driver = {
+	.driver = {
+		.name = "rk3036-codec-platform",
+		.of_match_table = of_match_ptr(rk3036_codec_of_match),
+	},
+	.probe = rk3036_codec_platform_probe,
+	.remove = rk3036_codec_platform_remove,
+};
+
+module_platform_driver(rk3036_codec_platform_driver);
+
+MODULE_AUTHOR("Rockchip Inc.");
+MODULE_DESCRIPTION("Rockchip rk3036 codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/inno_rk3036.h b/sound/soc/codecs/inno_rk3036.h
new file mode 100644
index 0000000..da759c6
--- /dev/null
+++ b/sound/soc/codecs/inno_rk3036.h
@@ -0,0 +1,123 @@
+/*
+ * Driver of Inno Codec for rk3036 by Rockchip Inc.
+ *
+ * Author: Zheng ShunQian<zhengsq@rock-chips.com>
+ */
+
+#ifndef _INNO_RK3036_CODEC_H
+#define _INNO_RK3036_CODEC_H
+
+/* codec registers */
+#define INNO_R00	0x00
+#define INNO_R01	0x0c
+#define INNO_R02	0x10
+#define INNO_R03	0x14
+#define INNO_R04	0x88
+#define INNO_R05	0x8c
+#define INNO_R06	0x90
+#define INNO_R07	0x94
+#define INNO_R08	0x98
+#define INNO_R09	0x9c
+#define INNO_R10	0xa0
+
+/* register bit filed */
+#define INNO_R00_CSR_RESET		(0x0 << 0) /*codec system reset*/
+#define INNO_R00_CSR_WORK		(0x1 << 0)
+#define INNO_R00_CDCR_RESET		(0x0 << 1) /*codec digital core reset*/
+#define INNO_R00_CDCR_WORK		(0x1 << 1)
+#define INNO_R00_PRB_DISABLE		(0x0 << 6) /*power reset bypass*/
+#define INNO_R00_PRB_ENABLE		(0x1 << 6)
+
+#define INNO_R01_I2SMODE_MSK		(0x1 << 4)
+#define INNO_R01_I2SMODE_SLAVE		(0x0 << 4)
+#define INNO_R01_I2SMODE_MASTER		(0x1 << 4)
+#define INNO_R01_PINDIR_MSK		(0x1 << 5)
+#define INNO_R01_PINDIR_IN_SLAVE	(0x0 << 5) /*direction of pin*/
+#define INNO_R01_PINDIR_OUT_MASTER	(0x1 << 5)
+
+#define INNO_R02_LRS_MSK		(0x1 << 2)
+#define INNO_R02_LRS_NORMAL		(0x0 << 2) /*DAC Left Right Swap*/
+#define INNO_R02_LRS_SWAP		(0x1 << 2)
+#define INNO_R02_DACM_MSK		(0x3 << 3)
+#define INNO_R02_DACM_PCM		(0x3 << 3) /*DAC Mode*/
+#define INNO_R02_DACM_I2S		(0x2 << 3)
+#define INNO_R02_DACM_LJM		(0x1 << 3)
+#define INNO_R02_DACM_RJM		(0x0 << 3)
+#define INNO_R02_VWL_MSK		(0x3 << 5)
+#define INNO_R02_VWL_32BIT		(0x3 << 5) /*1/2Frame Valid Word Len*/
+#define INNO_R02_VWL_24BIT		(0x2 << 5)
+#define INNO_R02_VWL_20BIT		(0x1 << 5)
+#define INNO_R02_VWL_16BIT		(0x0 << 5)
+#define INNO_R02_LRCP_MSK		(0x1 << 7)
+#define INNO_R02_LRCP_NORMAL		(0x0 << 7) /*Left Right Polarity*/
+#define INNO_R02_LRCP_REVERSAL		(0x1 << 7)
+
+#define INNO_R03_BCP_MSK		(0x1 << 0)
+#define INNO_R03_BCP_NORMAL		(0x0 << 0) /*DAC bit clock polarity*/
+#define INNO_R03_BCP_REVERSAL		(0x1 << 0)
+#define INNO_R03_DACR_MSK		(0x1 << 1)
+#define INNO_R03_DACR_RESET		(0x0 << 1) /*DAC Reset*/
+#define INNO_R03_DACR_WORK		(0x1 << 1)
+#define INNO_R03_FWL_MSK		(0x3 << 2)
+#define INNO_R03_FWL_32BIT		(0x3 << 2) /*1/2Frame Word Length*/
+#define INNO_R03_FWL_24BIT		(0x2 << 2)
+#define INNO_R03_FWL_20BIT		(0x1 << 2)
+#define INNO_R03_FWL_16BIT		(0x0 << 2)
+
+#define INNO_R04_DACR_SW_SHIFT		0
+#define INNO_R04_DACL_SW_SHIFT		1
+#define INNO_R04_DACR_CLK_SHIFT		2
+#define INNO_R04_DACL_CLK_SHIFT		3
+#define INNO_R04_DACR_VREF_SHIFT	4
+#define INNO_R04_DACL_VREF_SHIFT	5
+
+#define INNO_R05_HPR_EN_SHIFT		0
+#define INNO_R05_HPL_EN_SHIFT		1
+#define INNO_R05_HPR_WORK_SHIFT		2
+#define INNO_R05_HPL_WORK_SHIFT		3
+
+#define INNO_R06_VOUTR_CZ_SHIFT		0
+#define INNO_R06_VOUTL_CZ_SHIFT		1
+#define INNO_R06_DACR_HILO_VREF_SHIFT	2
+#define INNO_R06_DACL_HILO_VREF_SHIFT	3
+#define INNO_R06_DAC_EN_SHIFT		5
+
+#define INNO_R06_DAC_PRECHARGE		(0x0 << 4) /*PreCharge control for DAC*/
+#define INNO_R06_DAC_DISCHARGE		(0x1 << 4)
+
+#define INNO_HP_GAIN_SHIFT		0
+/* Gain of output, 1.5db step: -39db(0x0) ~ 0db(0x1a) ~ 6db(0x1f) */
+#define INNO_HP_GAIN_0DB		0x1a
+#define INNO_HP_GAIN_N39DB		0x0
+
+#define INNO_R09_HP_ANTIPOP_MSK		0x3
+#define INNO_R09_HP_ANTIPOP_OFF		0x1
+#define INNO_R09_HP_ANTIPOP_ON		0x2
+#define INNO_R09_HPR_ANITPOP_SHIFT	0
+#define INNO_R09_HPL_ANITPOP_SHIFT	2
+#define INNO_R09_HPR_MUTE_SHIFT		4
+#define INNO_R09_HPL_MUTE_SHIFT		5
+#define INNO_R09_DACR_SWITCH_SHIFT	6
+#define INNO_R09_DACL_SWITCH_SHIFT	7
+
+#define INNO_R10_CHARGE_SEL_CUR_400I_YES	(0x0 << 0)
+#define INNO_R10_CHARGE_SEL_CUR_400I_NO		(0x1 << 0)
+#define INNO_R10_CHARGE_SEL_CUR_260I_YES	(0x0 << 1)
+#define INNO_R10_CHARGE_SEL_CUR_260I_NO		(0x1 << 1)
+#define INNO_R10_CHARGE_SEL_CUR_130I_YES	(0x0 << 2)
+#define INNO_R10_CHARGE_SEL_CUR_130I_NO		(0x1 << 2)
+#define INNO_R10_CHARGE_SEL_CUR_100I_YES	(0x0 << 3)
+#define INNO_R10_CHARGE_SEL_CUR_100I_NO		(0x1 << 3)
+#define INNO_R10_CHARGE_SEL_CUR_050I_YES	(0x0 << 4)
+#define INNO_R10_CHARGE_SEL_CUR_050I_NO		(0x1 << 4)
+#define INNO_R10_CHARGE_SEL_CUR_027I_YES	(0x0 << 5)
+#define INNO_R10_CHARGE_SEL_CUR_027I_NO		(0x1 << 5)
+
+#define INNO_R10_MAX_CUR (INNO_R10_CHARGE_SEL_CUR_400I_YES | \
+			  INNO_R10_CHARGE_SEL_CUR_260I_YES | \
+			  INNO_R10_CHARGE_SEL_CUR_130I_YES | \
+			  INNO_R10_CHARGE_SEL_CUR_100I_YES | \
+			  INNO_R10_CHARGE_SEL_CUR_050I_YES | \
+			  INNO_R10_CHARGE_SEL_CUR_027I_YES)
+
+#endif
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
index f5e3dce..5b1dfb1 100644
--- a/sound/soc/codecs/max98357a.c
+++ b/sound/soc/codecs/max98357a.c
@@ -12,6 +12,7 @@
  * max98357a.c -- MAX98357A ALSA SoC Codec driver
  */
 
+#include <linux/acpi.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
@@ -123,10 +124,19 @@
 MODULE_DEVICE_TABLE(of, max98357a_device_id);
 #endif
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id max98357a_acpi_match[] = {
+	{ "MX98357A", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, max98357a_acpi_match);
+#endif
+
 static struct platform_driver max98357a_platform_driver = {
 	.driver = {
 		.name = "max98357a",
 		.of_match_table = of_match_ptr(max98357a_device_id),
+		.acpi_match_table = ACPI_PTR(max98357a_acpi_match),
 	},
 	.probe	= max98357a_platform_probe,
 	.remove = max98357a_platform_remove,
diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c
deleted file mode 100644
index 08bb486..0000000
--- a/sound/soc/codecs/pcm1792a.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * PCM1792A ASoC codec driver
- *
- * Copyright (c) Amarula Solutions B.V. 2013
- *
- *     Michael Trimarchi <michael@amarulasolutions.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-#include <sound/tlv.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-
-#include "pcm1792a.h"
-
-#define PCM1792A_DAC_VOL_LEFT	0x10
-#define PCM1792A_DAC_VOL_RIGHT	0x11
-#define PCM1792A_FMT_CONTROL	0x12
-#define PCM1792A_MODE_CONTROL	0x13
-#define PCM1792A_SOFT_MUTE	PCM1792A_FMT_CONTROL
-
-#define PCM1792A_FMT_MASK	0x70
-#define PCM1792A_FMT_SHIFT	4
-#define PCM1792A_MUTE_MASK	0x01
-#define PCM1792A_MUTE_SHIFT	0
-#define PCM1792A_ATLD_ENABLE	(1 << 7)
-
-static const struct reg_default pcm1792a_reg_defaults[] = {
-	{ 0x10, 0xff },
-	{ 0x11, 0xff },
-	{ 0x12, 0x50 },
-	{ 0x13, 0x00 },
-	{ 0x14, 0x00 },
-	{ 0x15, 0x01 },
-	{ 0x16, 0x00 },
-	{ 0x17, 0x00 },
-};
-
-static bool pcm1792a_accessible_reg(struct device *dev, unsigned int reg)
-{
-	return reg >= 0x10 && reg <= 0x17;
-}
-
-static bool pcm1792a_writeable_reg(struct device *dev, unsigned register reg)
-{
-	bool accessible;
-
-	accessible = pcm1792a_accessible_reg(dev, reg);
-
-	return accessible && reg != 0x16 && reg != 0x17;
-}
-
-struct pcm1792a_private {
-	struct regmap *regmap;
-	unsigned int format;
-	unsigned int rate;
-};
-
-static int pcm1792a_set_dai_fmt(struct snd_soc_dai *codec_dai,
-                             unsigned int format)
-{
-	struct snd_soc_codec *codec = codec_dai->codec;
-	struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
-
-	priv->format = format;
-
-	return 0;
-}
-
-static int pcm1792a_digital_mute(struct snd_soc_dai *dai, int mute)
-{
-	struct snd_soc_codec *codec = dai->codec;
-	struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
-	int ret;
-
-	ret = regmap_update_bits(priv->regmap, PCM1792A_SOFT_MUTE,
-				 PCM1792A_MUTE_MASK, !!mute);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static int pcm1792a_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 pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
-	int val = 0, ret;
-
-	priv->rate = params_rate(params);
-
-	switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_RIGHT_J:
-		switch (params_width(params)) {
-		case 24:
-		case 32:
-			val = 2;
-			break;
-		case 16:
-			val = 0;
-			break;
-		default:
-			return -EINVAL;
-		}
-		break;
-	case SND_SOC_DAIFMT_I2S:
-		switch (params_width(params)) {
-		case 24:
-		case 32:
-			val = 5;
-			break;
-		case 16:
-			val = 4;
-			break;
-		default:
-			return -EINVAL;
-		}
-		break;
-	default:
-		dev_err(codec->dev, "Invalid DAI format\n");
-		return -EINVAL;
-	}
-
-	val = val << PCM1792A_FMT_SHIFT | PCM1792A_ATLD_ENABLE;
-
-	ret = regmap_update_bits(priv->regmap, PCM1792A_FMT_CONTROL,
-				 PCM1792A_FMT_MASK | PCM1792A_ATLD_ENABLE, val);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static const struct snd_soc_dai_ops pcm1792a_dai_ops = {
-	.set_fmt	= pcm1792a_set_dai_fmt,
-	.hw_params	= pcm1792a_hw_params,
-	.digital_mute	= pcm1792a_digital_mute,
-};
-
-static const DECLARE_TLV_DB_SCALE(pcm1792a_dac_tlv, -12000, 50, 1);
-
-static const struct snd_kcontrol_new pcm1792a_controls[] = {
-	SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1792A_DAC_VOL_LEFT,
-			 PCM1792A_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0,
-			 pcm1792a_dac_tlv),
-	SOC_SINGLE("DAC Invert Output Switch", PCM1792A_MODE_CONTROL, 7, 1, 0),
-	SOC_SINGLE("DAC Rolloff Filter Switch", PCM1792A_MODE_CONTROL, 1, 1, 0),
-};
-
-static const struct snd_soc_dapm_widget pcm1792a_dapm_widgets[] = {
-SND_SOC_DAPM_OUTPUT("IOUTL+"),
-SND_SOC_DAPM_OUTPUT("IOUTL-"),
-SND_SOC_DAPM_OUTPUT("IOUTR+"),
-SND_SOC_DAPM_OUTPUT("IOUTR-"),
-};
-
-static const struct snd_soc_dapm_route pcm1792a_dapm_routes[] = {
-	{ "IOUTL+", NULL, "Playback" },
-	{ "IOUTL-", NULL, "Playback" },
-	{ "IOUTR+", NULL, "Playback" },
-	{ "IOUTR-", NULL, "Playback" },
-};
-
-static struct snd_soc_dai_driver pcm1792a_dai = {
-	.name = "pcm1792a-hifi",
-	.playback = {
-		.stream_name = "Playback",
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = PCM1792A_RATES,
-		.formats = PCM1792A_FORMATS, },
-	.ops = &pcm1792a_dai_ops,
-};
-
-static const struct of_device_id pcm1792a_of_match[] = {
-	{ .compatible = "ti,pcm1792a", },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, pcm1792a_of_match);
-
-static const struct regmap_config pcm1792a_regmap = {
-	.reg_bits		= 8,
-	.val_bits		= 8,
-	.max_register		= 23,
-	.reg_defaults		= pcm1792a_reg_defaults,
-	.num_reg_defaults	= ARRAY_SIZE(pcm1792a_reg_defaults),
-	.writeable_reg		= pcm1792a_writeable_reg,
-	.readable_reg		= pcm1792a_accessible_reg,
-};
-
-static struct snd_soc_codec_driver soc_codec_dev_pcm1792a = {
-	.controls		= pcm1792a_controls,
-	.num_controls		= ARRAY_SIZE(pcm1792a_controls),
-	.dapm_widgets		= pcm1792a_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(pcm1792a_dapm_widgets),
-	.dapm_routes		= pcm1792a_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(pcm1792a_dapm_routes),
-};
-
-static int pcm1792a_spi_probe(struct spi_device *spi)
-{
-	struct pcm1792a_private *pcm1792a;
-	int ret;
-
-	pcm1792a = devm_kzalloc(&spi->dev, sizeof(struct pcm1792a_private),
-				GFP_KERNEL);
-	if (!pcm1792a)
-		return -ENOMEM;
-
-	spi_set_drvdata(spi, pcm1792a);
-
-	pcm1792a->regmap = devm_regmap_init_spi(spi, &pcm1792a_regmap);
-	if (IS_ERR(pcm1792a->regmap)) {
-		ret = PTR_ERR(pcm1792a->regmap);
-		dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
-		return ret;
-	}
-
-	return snd_soc_register_codec(&spi->dev,
-			&soc_codec_dev_pcm1792a, &pcm1792a_dai, 1);
-}
-
-static int pcm1792a_spi_remove(struct spi_device *spi)
-{
-	snd_soc_unregister_codec(&spi->dev);
-	return 0;
-}
-
-static const struct spi_device_id pcm1792a_spi_ids[] = {
-	{ "pcm1792a", 0 },
-	{ },
-};
-MODULE_DEVICE_TABLE(spi, pcm1792a_spi_ids);
-
-static struct spi_driver pcm1792a_codec_driver = {
-	.driver = {
-		.name = "pcm1792a",
-		.of_match_table = of_match_ptr(pcm1792a_of_match),
-	},
-	.id_table = pcm1792a_spi_ids,
-	.probe = pcm1792a_spi_probe,
-	.remove = pcm1792a_spi_remove,
-};
-
-module_spi_driver(pcm1792a_codec_driver);
-
-MODULE_DESCRIPTION("ASoC PCM1792A driver");
-MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c
new file mode 100644
index 0000000..a56c7b7
--- /dev/null
+++ b/sound/soc/codecs/pcm179x.c
@@ -0,0 +1,271 @@
+/*
+ * PCM179X ASoC codec driver
+ *
+ * Copyright (c) Amarula Solutions B.V. 2013
+ *
+ *     Michael Trimarchi <michael@amarulasolutions.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include "pcm179x.h"
+
+#define PCM179X_DAC_VOL_LEFT	0x10
+#define PCM179X_DAC_VOL_RIGHT	0x11
+#define PCM179X_FMT_CONTROL	0x12
+#define PCM179X_MODE_CONTROL	0x13
+#define PCM179X_SOFT_MUTE	PCM179X_FMT_CONTROL
+
+#define PCM179X_FMT_MASK	0x70
+#define PCM179X_FMT_SHIFT	4
+#define PCM179X_MUTE_MASK	0x01
+#define PCM179X_MUTE_SHIFT	0
+#define PCM179X_ATLD_ENABLE	(1 << 7)
+
+static const struct reg_default pcm179x_reg_defaults[] = {
+	{ 0x10, 0xff },
+	{ 0x11, 0xff },
+	{ 0x12, 0x50 },
+	{ 0x13, 0x00 },
+	{ 0x14, 0x00 },
+	{ 0x15, 0x01 },
+	{ 0x16, 0x00 },
+	{ 0x17, 0x00 },
+};
+
+static bool pcm179x_accessible_reg(struct device *dev, unsigned int reg)
+{
+	return reg >= 0x10 && reg <= 0x17;
+}
+
+static bool pcm179x_writeable_reg(struct device *dev, unsigned register reg)
+{
+	bool accessible;
+
+	accessible = pcm179x_accessible_reg(dev, reg);
+
+	return accessible && reg != 0x16 && reg != 0x17;
+}
+
+struct pcm179x_private {
+	struct regmap *regmap;
+	unsigned int format;
+	unsigned int rate;
+};
+
+static int pcm179x_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int format)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec);
+
+	priv->format = format;
+
+	return 0;
+}
+
+static int pcm179x_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	ret = regmap_update_bits(priv->regmap, PCM179X_SOFT_MUTE,
+				 PCM179X_MUTE_MASK, !!mute);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int pcm179x_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 pcm179x_private *priv = snd_soc_codec_get_drvdata(codec);
+	int val = 0, ret;
+
+	priv->rate = params_rate(params);
+
+	switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		switch (params_width(params)) {
+		case 24:
+		case 32:
+			val = 2;
+			break;
+		case 16:
+			val = 0;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		switch (params_width(params)) {
+		case 24:
+		case 32:
+			val = 5;
+			break;
+		case 16:
+			val = 4;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		dev_err(codec->dev, "Invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	val = val << PCM179X_FMT_SHIFT | PCM179X_ATLD_ENABLE;
+
+	ret = regmap_update_bits(priv->regmap, PCM179X_FMT_CONTROL,
+				 PCM179X_FMT_MASK | PCM179X_ATLD_ENABLE, val);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops pcm179x_dai_ops = {
+	.set_fmt	= pcm179x_set_dai_fmt,
+	.hw_params	= pcm179x_hw_params,
+	.digital_mute	= pcm179x_digital_mute,
+};
+
+static const DECLARE_TLV_DB_SCALE(pcm179x_dac_tlv, -12000, 50, 1);
+
+static const struct snd_kcontrol_new pcm179x_controls[] = {
+	SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM179X_DAC_VOL_LEFT,
+			 PCM179X_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0,
+			 pcm179x_dac_tlv),
+	SOC_SINGLE("DAC Invert Output Switch", PCM179X_MODE_CONTROL, 7, 1, 0),
+	SOC_SINGLE("DAC Rolloff Filter Switch", PCM179X_MODE_CONTROL, 1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget pcm179x_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("IOUTL+"),
+SND_SOC_DAPM_OUTPUT("IOUTL-"),
+SND_SOC_DAPM_OUTPUT("IOUTR+"),
+SND_SOC_DAPM_OUTPUT("IOUTR-"),
+};
+
+static const struct snd_soc_dapm_route pcm179x_dapm_routes[] = {
+	{ "IOUTL+", NULL, "Playback" },
+	{ "IOUTL-", NULL, "Playback" },
+	{ "IOUTR+", NULL, "Playback" },
+	{ "IOUTR-", NULL, "Playback" },
+};
+
+static struct snd_soc_dai_driver pcm179x_dai = {
+	.name = "pcm179x-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = PCM1792A_RATES,
+		.formats = PCM1792A_FORMATS, },
+	.ops = &pcm179x_dai_ops,
+};
+
+static const struct of_device_id pcm179x_of_match[] = {
+	{ .compatible = "ti,pcm1792a", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm179x_of_match);
+
+static const struct regmap_config pcm179x_regmap = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+	.max_register		= 23,
+	.reg_defaults		= pcm179x_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(pcm179x_reg_defaults),
+	.writeable_reg		= pcm179x_writeable_reg,
+	.readable_reg		= pcm179x_accessible_reg,
+};
+
+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),
+};
+
+static int pcm179x_spi_probe(struct spi_device *spi)
+{
+	struct pcm179x_private *pcm179x;
+	int ret;
+
+	pcm179x = devm_kzalloc(&spi->dev, sizeof(struct pcm179x_private),
+				GFP_KERNEL);
+	if (!pcm179x)
+		return -ENOMEM;
+
+	spi_set_drvdata(spi, pcm179x);
+
+	pcm179x->regmap = devm_regmap_init_spi(spi, &pcm179x_regmap);
+	if (IS_ERR(pcm179x->regmap)) {
+		ret = PTR_ERR(pcm179x->regmap);
+		dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
+		return ret;
+	}
+
+	return snd_soc_register_codec(&spi->dev,
+			&soc_codec_dev_pcm179x, &pcm179x_dai, 1);
+}
+
+static int pcm179x_spi_remove(struct spi_device *spi)
+{
+	snd_soc_unregister_codec(&spi->dev);
+	return 0;
+}
+
+static const struct spi_device_id pcm179x_spi_ids[] = {
+	{ "pcm179x", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, pcm179x_spi_ids);
+
+static struct spi_driver pcm179x_codec_driver = {
+	.driver = {
+		.name = "pcm179x",
+		.of_match_table = of_match_ptr(pcm179x_of_match),
+	},
+	.id_table = pcm179x_spi_ids,
+	.probe = pcm179x_spi_probe,
+	.remove = pcm179x_spi_remove,
+};
+
+module_spi_driver(pcm179x_codec_driver);
+
+MODULE_DESCRIPTION("ASoC PCM179X driver");
+MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm1792a.h b/sound/soc/codecs/pcm179x.h
similarity index 91%
rename from sound/soc/codecs/pcm1792a.h
rename to sound/soc/codecs/pcm179x.h
index 51d5470..c6fdc06 100644
--- a/sound/soc/codecs/pcm1792a.h
+++ b/sound/soc/codecs/pcm179x.h
@@ -1,5 +1,5 @@
 /*
- * definitions for PCM1792A
+ * definitions for PCM179X
  *
  * Copyright 2013 Amarula Solutions
  *
@@ -14,8 +14,8 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __PCM1792A_H__
-#define __PCM1792A_H__
+#ifndef __PCM179X_H__
+#define __PCM179X_H__
 
 #define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \
 			SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
diff --git a/sound/soc/codecs/pcm3168a-i2c.c b/sound/soc/codecs/pcm3168a-i2c.c
new file mode 100644
index 0000000..6feb090
--- /dev/null
+++ b/sound/soc/codecs/pcm3168a-i2c.c
@@ -0,0 +1,66 @@
+/*
+ * PCM3168A codec i2c driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <sound/soc.h>
+
+#include "pcm3168a.h"
+
+static int pcm3168a_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_i2c(i2c, &pcm3168a_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return pcm3168a_probe(&i2c->dev, regmap);
+}
+
+static int pcm3168a_i2c_remove(struct i2c_client *i2c)
+{
+	pcm3168a_remove(&i2c->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id pcm3168a_i2c_id[] = {
+	{ "pcm3168a", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pcm3168a_i2c_id);
+
+static const struct of_device_id pcm3168a_of_match[] = {
+	{ .compatible = "ti,pcm3168a", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm3168a_of_match);
+
+static struct i2c_driver pcm3168a_i2c_driver = {
+	.probe		= pcm3168a_i2c_probe,
+	.remove		= pcm3168a_i2c_remove,
+	.id_table	= pcm3168a_i2c_id,
+	.driver		= {
+		.name	= "pcm3168a",
+		.of_match_table = pcm3168a_of_match,
+		.pm		= &pcm3168a_pm_ops,
+	},
+};
+module_i2c_driver(pcm3168a_i2c_driver);
+
+MODULE_DESCRIPTION("PCM3168A I2C codec driver");
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3168a-spi.c b/sound/soc/codecs/pcm3168a-spi.c
new file mode 100644
index 0000000..03945a2
--- /dev/null
+++ b/sound/soc/codecs/pcm3168a-spi.c
@@ -0,0 +1,65 @@
+/*
+ * PCM3168A codec spi driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include <sound/soc.h>
+
+#include "pcm3168a.h"
+
+static int pcm3168a_spi_probe(struct spi_device *spi)
+{
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_spi(spi, &pcm3168a_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return pcm3168a_probe(&spi->dev, regmap);
+}
+
+static int pcm3168a_spi_remove(struct spi_device *spi)
+{
+	pcm3168a_remove(&spi->dev);
+
+	return 0;
+}
+
+static const struct spi_device_id pcm3168a_spi_id[] = {
+	{ "pcm3168a", },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, pcm3168a_spi_id);
+
+static const struct of_device_id pcm3168a_of_match[] = {
+	{ .compatible = "ti,pcm3168a", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm3168a_of_match);
+
+static struct spi_driver pcm3168a_spi_driver = {
+	.probe		= pcm3168a_spi_probe,
+	.remove		= pcm3168a_spi_remove,
+	.id_table	= pcm3168a_spi_id,
+	.driver = {
+		.name	= "pcm3168a",
+		.of_match_table = pcm3168a_of_match,
+		.pm		= &pcm3168a_pm_ops,
+	},
+};
+module_spi_driver(pcm3168a_spi_driver);
+
+MODULE_DESCRIPTION("PCM3168A SPI codec driver");
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
new file mode 100644
index 0000000..44b268a
--- /dev/null
+++ b/sound/soc/codecs/pcm3168a.c
@@ -0,0 +1,767 @@
+/*
+ * PCM3168A codec driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "pcm3168a.h"
+
+#define PCM3168A_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+			 SNDRV_PCM_FMTBIT_S24_3LE | \
+			 SNDRV_PCM_FMTBIT_S24_LE | \
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+#define PCM3168A_FMT_I2S		0x0
+#define PCM3168A_FMT_LEFT_J		0x1
+#define PCM3168A_FMT_RIGHT_J		0x2
+#define PCM3168A_FMT_RIGHT_J_16		0x3
+#define PCM3168A_FMT_DSP_A		0x4
+#define PCM3168A_FMT_DSP_B		0x5
+#define PCM3168A_FMT_DSP_MASK		0x4
+
+#define PCM3168A_NUM_SUPPLIES 6
+static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = {
+	"VDD1",
+	"VDD2",
+	"VCCAD1",
+	"VCCAD2",
+	"VCCDA1",
+	"VCCDA2"
+};
+
+struct pcm3168a_priv {
+	struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES];
+	struct regmap *regmap;
+	struct clk *scki;
+	bool adc_master_mode;
+	bool dac_master_mode;
+	unsigned long sysclk;
+	unsigned int adc_fmt;
+	unsigned int dac_fmt;
+};
+
+static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d1_roll_off, PCM3168A_DAC_OP_FLT,
+		PCM3168A_DAC_FLT_SHIFT, pcm3168a_roll_off);
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d2_roll_off, PCM3168A_DAC_OP_FLT,
+		PCM3168A_DAC_FLT_SHIFT + 1, pcm3168a_roll_off);
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d3_roll_off, PCM3168A_DAC_OP_FLT,
+		PCM3168A_DAC_FLT_SHIFT + 2, pcm3168a_roll_off);
+static SOC_ENUM_SINGLE_DECL(pcm3168a_d4_roll_off, PCM3168A_DAC_OP_FLT,
+		PCM3168A_DAC_FLT_SHIFT + 3, pcm3168a_roll_off);
+
+static const char *const pcm3168a_volume_type[] = {
+		"Individual", "Master + Individual" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_volume_type, PCM3168A_DAC_ATT_DEMP_ZF,
+		PCM3168A_DAC_ATMDDA_SHIFT, pcm3168a_volume_type);
+
+static const char *const pcm3168a_att_speed_mult[] = { "2048", "4096" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_att_mult, PCM3168A_DAC_ATT_DEMP_ZF,
+		PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_att_speed_mult);
+
+static const char *const pcm3168a_demp[] = {
+		"Disabled", "48khz", "44.1khz", "32khz" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_demp, PCM3168A_DAC_ATT_DEMP_ZF,
+		PCM3168A_DAC_DEMP_SHIFT, pcm3168a_demp);
+
+static const char *const pcm3168a_zf_func[] = {
+		"DAC 1/2/3/4 AND", "DAC 1/2/3/4 OR", "DAC 1/2/3 AND",
+		"DAC 1/2/3 OR", "DAC 4 AND", "DAC 4 OR" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_func, PCM3168A_DAC_ATT_DEMP_ZF,
+		PCM3168A_DAC_AZRO_SHIFT, pcm3168a_zf_func);
+
+static const char *const pcm3168a_pol[] = { "Active High", "Active Low" };
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_pol, PCM3168A_DAC_ATT_DEMP_ZF,
+		PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_pol);
+
+static const char *const pcm3168a_con[] = { "Differential", "Single-Ended" };
+
+static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc1_con, PCM3168A_ADC_SEAD,
+				0, 1, pcm3168a_con);
+static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc2_con, PCM3168A_ADC_SEAD,
+				2, 3, pcm3168a_con);
+static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc3_con, PCM3168A_ADC_SEAD,
+				4, 5, pcm3168a_con);
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_volume_type, PCM3168A_ADC_ATT_OVF,
+		PCM3168A_ADC_ATMDAD_SHIFT, pcm3168a_volume_type);
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_att_mult, PCM3168A_ADC_ATT_OVF,
+		PCM3168A_ADC_ATSPAD_SHIFT, pcm3168a_att_speed_mult);
+
+static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_ov_pol, PCM3168A_ADC_ATT_OVF,
+		PCM3168A_ADC_OVFP_SHIFT, pcm3168a_pol);
+
+/* -100db to 0db, register values 0-54 cause mute */
+static const DECLARE_TLV_DB_SCALE(pcm3168a_dac_tlv, -10050, 50, 1);
+
+/* -100db to 20db, register values 0-14 cause mute */
+static const DECLARE_TLV_DB_SCALE(pcm3168a_adc_tlv, -10050, 50, 1);
+
+static const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
+	SOC_SINGLE("DAC Power-Save Switch", PCM3168A_DAC_PWR_MST_FMT,
+			PCM3168A_DAC_PSMDA_SHIFT, 1, 1),
+	SOC_ENUM("DAC1 Digital Filter roll-off", pcm3168a_d1_roll_off),
+	SOC_ENUM("DAC2 Digital Filter roll-off", pcm3168a_d2_roll_off),
+	SOC_ENUM("DAC3 Digital Filter roll-off", pcm3168a_d3_roll_off),
+	SOC_ENUM("DAC4 Digital Filter roll-off", pcm3168a_d4_roll_off),
+	SOC_DOUBLE("DAC1 Invert Switch", PCM3168A_DAC_INV, 0, 1, 1, 0),
+	SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0),
+	SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0),
+	SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0),
+	SOC_DOUBLE_STS("DAC1 Zero Flag", PCM3168A_DAC_ZERO, 0, 1, 1, 0),
+	SOC_DOUBLE_STS("DAC2 Zero Flag", PCM3168A_DAC_ZERO, 2, 3, 1, 0),
+	SOC_DOUBLE_STS("DAC3 Zero Flag", PCM3168A_DAC_ZERO, 4, 5, 1, 0),
+	SOC_DOUBLE_STS("DAC4 Zero Flag", PCM3168A_DAC_ZERO, 6, 7, 1, 0),
+	SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type),
+	SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult),
+	SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp),
+	SOC_ENUM("DAC Zero Flag Function", pcm3168a_dac_zf_func),
+	SOC_ENUM("DAC Zero Flag Polarity", pcm3168a_dac_zf_pol),
+	SOC_SINGLE_RANGE_TLV("Master Playback Volume",
+			PCM3168A_DAC_VOL_MASTER, 0, 54, 255, 0,
+			pcm3168a_dac_tlv),
+	SOC_DOUBLE_R_RANGE_TLV("DAC1 Playback Volume",
+			PCM3168A_DAC_VOL_CHAN_START,
+			PCM3168A_DAC_VOL_CHAN_START + 1,
+			0, 54, 255, 0, pcm3168a_dac_tlv),
+	SOC_DOUBLE_R_RANGE_TLV("DAC2 Playback Volume",
+			PCM3168A_DAC_VOL_CHAN_START + 2,
+			PCM3168A_DAC_VOL_CHAN_START + 3,
+			0, 54, 255, 0, pcm3168a_dac_tlv),
+	SOC_DOUBLE_R_RANGE_TLV("DAC3 Playback Volume",
+			PCM3168A_DAC_VOL_CHAN_START + 4,
+			PCM3168A_DAC_VOL_CHAN_START + 5,
+			0, 54, 255, 0, pcm3168a_dac_tlv),
+	SOC_DOUBLE_R_RANGE_TLV("DAC4 Playback Volume",
+			PCM3168A_DAC_VOL_CHAN_START + 6,
+			PCM3168A_DAC_VOL_CHAN_START + 7,
+			0, 54, 255, 0, pcm3168a_dac_tlv),
+	SOC_SINGLE("ADC1 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
+			PCM3168A_ADC_BYP_SHIFT, 1, 1),
+	SOC_SINGLE("ADC2 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
+			PCM3168A_ADC_BYP_SHIFT + 1, 1, 1),
+	SOC_SINGLE("ADC3 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
+			PCM3168A_ADC_BYP_SHIFT + 2, 1, 1),
+	SOC_ENUM("ADC1 Connection Type", pcm3168a_adc1_con),
+	SOC_ENUM("ADC2 Connection Type", pcm3168a_adc2_con),
+	SOC_ENUM("ADC3 Connection Type", pcm3168a_adc3_con),
+	SOC_DOUBLE("ADC1 Invert Switch", PCM3168A_ADC_INV, 0, 1, 1, 0),
+	SOC_DOUBLE("ADC2 Invert Switch", PCM3168A_ADC_INV, 2, 3, 1, 0),
+	SOC_DOUBLE("ADC3 Invert Switch", PCM3168A_ADC_INV, 4, 5, 1, 0),
+	SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0),
+	SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0),
+	SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0),
+	SOC_DOUBLE_STS("ADC1 Overflow Flag", PCM3168A_ADC_OV, 0, 1, 1, 0),
+	SOC_DOUBLE_STS("ADC2 Overflow Flag", PCM3168A_ADC_OV, 2, 3, 1, 0),
+	SOC_DOUBLE_STS("ADC3 Overflow Flag", PCM3168A_ADC_OV, 4, 5, 1, 0),
+	SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type),
+	SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult),
+	SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol),
+	SOC_SINGLE_RANGE_TLV("Master Capture Volume",
+			PCM3168A_ADC_VOL_MASTER, 0, 14, 255, 0,
+			pcm3168a_adc_tlv),
+	SOC_DOUBLE_R_RANGE_TLV("ADC1 Capture Volume",
+			PCM3168A_ADC_VOL_CHAN_START,
+			PCM3168A_ADC_VOL_CHAN_START + 1,
+			0, 14, 255, 0, pcm3168a_adc_tlv),
+	SOC_DOUBLE_R_RANGE_TLV("ADC2 Capture Volume",
+			PCM3168A_ADC_VOL_CHAN_START + 2,
+			PCM3168A_ADC_VOL_CHAN_START + 3,
+			0, 14, 255, 0, pcm3168a_adc_tlv),
+	SOC_DOUBLE_R_RANGE_TLV("ADC3 Capture Volume",
+			PCM3168A_ADC_VOL_CHAN_START + 4,
+			PCM3168A_ADC_VOL_CHAN_START + 5,
+			0, 14, 255, 0, pcm3168a_adc_tlv)
+};
+
+static const struct snd_soc_dapm_widget pcm3168a_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC1", "Playback", PCM3168A_DAC_OP_FLT,
+			PCM3168A_DAC_OPEDA_SHIFT, 1),
+	SND_SOC_DAPM_DAC("DAC2", "Playback", PCM3168A_DAC_OP_FLT,
+			PCM3168A_DAC_OPEDA_SHIFT + 1, 1),
+	SND_SOC_DAPM_DAC("DAC3", "Playback", PCM3168A_DAC_OP_FLT,
+			PCM3168A_DAC_OPEDA_SHIFT + 2, 1),
+	SND_SOC_DAPM_DAC("DAC4", "Playback", PCM3168A_DAC_OP_FLT,
+			PCM3168A_DAC_OPEDA_SHIFT + 3, 1),
+
+	SND_SOC_DAPM_OUTPUT("AOUT1L"),
+	SND_SOC_DAPM_OUTPUT("AOUT1R"),
+	SND_SOC_DAPM_OUTPUT("AOUT2L"),
+	SND_SOC_DAPM_OUTPUT("AOUT2R"),
+	SND_SOC_DAPM_OUTPUT("AOUT3L"),
+	SND_SOC_DAPM_OUTPUT("AOUT3R"),
+	SND_SOC_DAPM_OUTPUT("AOUT4L"),
+	SND_SOC_DAPM_OUTPUT("AOUT4R"),
+
+	SND_SOC_DAPM_ADC("ADC1", "Capture", PCM3168A_ADC_PWR_HPFB,
+			PCM3168A_ADC_PSVAD_SHIFT, 1),
+	SND_SOC_DAPM_ADC("ADC2", "Capture", PCM3168A_ADC_PWR_HPFB,
+			PCM3168A_ADC_PSVAD_SHIFT + 1, 1),
+	SND_SOC_DAPM_ADC("ADC3", "Capture", PCM3168A_ADC_PWR_HPFB,
+			PCM3168A_ADC_PSVAD_SHIFT + 2, 1),
+
+	SND_SOC_DAPM_INPUT("AIN1L"),
+	SND_SOC_DAPM_INPUT("AIN1R"),
+	SND_SOC_DAPM_INPUT("AIN2L"),
+	SND_SOC_DAPM_INPUT("AIN2R"),
+	SND_SOC_DAPM_INPUT("AIN3L"),
+	SND_SOC_DAPM_INPUT("AIN3R")
+};
+
+static const struct snd_soc_dapm_route pcm3168a_dapm_routes[] = {
+	/* Playback */
+	{ "AOUT1L", NULL, "DAC1" },
+	{ "AOUT1R", NULL, "DAC1" },
+
+	{ "AOUT2L", NULL, "DAC2" },
+	{ "AOUT2R", NULL, "DAC2" },
+
+	{ "AOUT3L", NULL, "DAC3" },
+	{ "AOUT3R", NULL, "DAC3" },
+
+	{ "AOUT4L", NULL, "DAC4" },
+	{ "AOUT4R", NULL, "DAC4" },
+
+	/* Capture */
+	{ "ADC1", NULL, "AIN1L" },
+	{ "ADC1", NULL, "AIN1R" },
+
+	{ "ADC2", NULL, "AIN2L" },
+	{ "ADC2", NULL, "AIN2R" },
+
+	{ "ADC3", NULL, "AIN3L" },
+	{ "ADC3", NULL, "AIN3R" }
+};
+
+static unsigned int pcm3168a_scki_ratios[] = {
+	768,
+	512,
+	384,
+	256,
+	192,
+	128
+};
+
+#define PCM3168A_NUM_SCKI_RATIOS_DAC	ARRAY_SIZE(pcm3168a_scki_ratios)
+#define PCM3168A_NUM_SCKI_RATIOS_ADC	(ARRAY_SIZE(pcm3168a_scki_ratios) - 2)
+
+#define PCM1368A_MAX_SYSCLK		36864000
+
+static int pcm3168a_reset(struct pcm3168a_priv *pcm3168a)
+{
+	int ret;
+
+	ret = regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE, 0);
+	if (ret)
+		return ret;
+
+	/* Internal reset is de-asserted after 3846 SCKI cycles */
+	msleep(DIV_ROUND_UP(3846 * 1000, pcm3168a->sysclk));
+
+	return regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE,
+			PCM3168A_MRST_MASK | PCM3168A_SRST_MASK);
+}
+
+static int pcm3168a_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
+
+	regmap_write(pcm3168a->regmap, PCM3168A_DAC_MUTE, mute ? 0xff : 0);
+
+	return 0;
+}
+
+static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(dai->codec);
+
+	if (freq > PCM1368A_MAX_SYSCLK)
+		return -EINVAL;
+
+	pcm3168a->sysclk = freq;
+
+	return 0;
+}
+
+static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
+			       unsigned int format, bool dac)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
+	u32 fmt, reg, mask, shift;
+	bool master_mode;
+
+	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_LEFT_J:
+		fmt = PCM3168A_FMT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		fmt = PCM3168A_FMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		fmt = PCM3168A_FMT_RIGHT_J;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		fmt = PCM3168A_FMT_DSP_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		fmt = PCM3168A_FMT_DSP_B;
+		break;
+	default:
+		dev_err(codec->dev, "unsupported dai format\n");
+		return -EINVAL;
+	}
+
+	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		master_mode = false;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		master_mode = true;
+		break;
+	default:
+		dev_err(codec->dev, "unsupported master/slave mode\n");
+		return -EINVAL;
+	}
+
+	switch (format & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (dac) {
+		reg = PCM3168A_DAC_PWR_MST_FMT;
+		mask = PCM3168A_DAC_FMT_MASK;
+		shift = PCM3168A_DAC_FMT_SHIFT;
+		pcm3168a->dac_master_mode = master_mode;
+		pcm3168a->dac_fmt = fmt;
+	} else {
+		reg = PCM3168A_ADC_MST_FMT;
+		mask = PCM3168A_ADC_FMTAD_MASK;
+		shift = PCM3168A_ADC_FMTAD_SHIFT;
+		pcm3168a->adc_master_mode = master_mode;
+		pcm3168a->adc_fmt = fmt;
+	}
+
+	regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
+
+	return 0;
+}
+
+static int pcm3168a_set_dai_fmt_dac(struct snd_soc_dai *dai,
+			       unsigned int format)
+{
+	return pcm3168a_set_dai_fmt(dai, format, true);
+}
+
+static int pcm3168a_set_dai_fmt_adc(struct snd_soc_dai *dai,
+			       unsigned int format)
+{
+	return pcm3168a_set_dai_fmt(dai, format, false);
+}
+
+static int pcm3168a_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 pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
+	bool tx, master_mode;
+	u32 val, mask, shift, reg;
+	unsigned int rate, channels, fmt, ratio, max_ratio;
+	int i, min_frame_size;
+	snd_pcm_format_t format;
+
+	rate = params_rate(params);
+	format = params_format(params);
+	channels = params_channels(params);
+
+	ratio = pcm3168a->sysclk / rate;
+
+	tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	if (tx) {
+		max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC;
+		reg = PCM3168A_DAC_PWR_MST_FMT;
+		mask = PCM3168A_DAC_MSDA_MASK;
+		shift = PCM3168A_DAC_MSDA_SHIFT;
+		master_mode = pcm3168a->dac_master_mode;
+		fmt = pcm3168a->dac_fmt;
+	} else {
+		max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC;
+		reg = PCM3168A_ADC_MST_FMT;
+		mask = PCM3168A_ADC_MSAD_MASK;
+		shift = PCM3168A_ADC_MSAD_SHIFT;
+		master_mode = pcm3168a->adc_master_mode;
+		fmt = pcm3168a->adc_fmt;
+	}
+
+	for (i = 0; i < max_ratio; i++) {
+		if (pcm3168a_scki_ratios[i] == ratio)
+			break;
+	}
+
+	if (i == max_ratio) {
+		dev_err(codec->dev, "unsupported sysclk ratio\n");
+		return -EINVAL;
+	}
+
+	min_frame_size = params_width(params) * 2;
+	switch (min_frame_size) {
+	case 32:
+		if (master_mode || (fmt != PCM3168A_FMT_RIGHT_J)) {
+			dev_err(codec->dev, "32-bit frames are supported only for slave mode using right justified\n");
+			return -EINVAL;
+		}
+		fmt = PCM3168A_FMT_RIGHT_J_16;
+		break;
+	case 48:
+		if (master_mode || (fmt & PCM3168A_FMT_DSP_MASK)) {
+			dev_err(codec->dev, "48-bit frames not supported in master mode, or slave mode using DSP\n");
+			return -EINVAL;
+		}
+		break;
+	case 64:
+		break;
+	default:
+		dev_err(codec->dev, "unsupported frame size: %d\n", min_frame_size);
+		return -EINVAL;
+	}
+
+	if (master_mode)
+		val = ((i + 1) << shift);
+	else
+		val = 0;
+
+	regmap_update_bits(pcm3168a->regmap, reg, mask, val);
+
+	if (tx) {
+		mask = PCM3168A_DAC_FMT_MASK;
+		shift = PCM3168A_DAC_FMT_SHIFT;
+	} else {
+		mask = PCM3168A_ADC_FMTAD_MASK;
+		shift = PCM3168A_ADC_FMTAD_SHIFT;
+	}
+
+	regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = {
+	.set_fmt	= pcm3168a_set_dai_fmt_dac,
+	.set_sysclk	= pcm3168a_set_dai_sysclk,
+	.hw_params	= pcm3168a_hw_params,
+	.digital_mute	= pcm3168a_digital_mute
+};
+
+static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = {
+	.set_fmt	= pcm3168a_set_dai_fmt_adc,
+	.set_sysclk	= pcm3168a_set_dai_sysclk,
+	.hw_params	= pcm3168a_hw_params
+};
+
+static struct snd_soc_dai_driver pcm3168a_dais[] = {
+	{
+		.name = "pcm3168a-dac",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = PCM3168A_FORMATS
+		},
+		.ops = &pcm3168a_dac_dai_ops
+	},
+	{
+		.name = "pcm3168a-adc",
+		.capture = {
+			.stream_name = "Capture",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = SNDRV_PCM_RATE_8000_96000,
+			.formats = PCM3168A_FORMATS
+		},
+		.ops = &pcm3168a_adc_dai_ops
+	},
+};
+
+static const struct reg_default pcm3168a_reg_default[] = {
+	{ PCM3168A_RST_SMODE, PCM3168A_MRST_MASK | PCM3168A_SRST_MASK },
+	{ PCM3168A_DAC_PWR_MST_FMT, 0x00 },
+	{ PCM3168A_DAC_OP_FLT, 0x00 },
+	{ PCM3168A_DAC_INV, 0x00 },
+	{ PCM3168A_DAC_MUTE, 0x00 },
+	{ PCM3168A_DAC_ZERO, 0x00 },
+	{ PCM3168A_DAC_ATT_DEMP_ZF, 0x00 },
+	{ PCM3168A_DAC_VOL_MASTER, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START + 1, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START + 2, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START + 3, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START + 4, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START + 5, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START + 6, 0xff },
+	{ PCM3168A_DAC_VOL_CHAN_START + 7, 0xff },
+	{ PCM3168A_ADC_SMODE, 0x00 },
+	{ PCM3168A_ADC_MST_FMT, 0x00 },
+	{ PCM3168A_ADC_PWR_HPFB, 0x00 },
+	{ PCM3168A_ADC_SEAD, 0x00 },
+	{ PCM3168A_ADC_INV, 0x00 },
+	{ PCM3168A_ADC_MUTE, 0x00 },
+	{ PCM3168A_ADC_OV, 0x00 },
+	{ PCM3168A_ADC_ATT_OVF, 0x00 },
+	{ PCM3168A_ADC_VOL_MASTER, 0xd3 },
+	{ PCM3168A_ADC_VOL_CHAN_START, 0xd3 },
+	{ PCM3168A_ADC_VOL_CHAN_START + 1, 0xd3 },
+	{ PCM3168A_ADC_VOL_CHAN_START + 2, 0xd3 },
+	{ PCM3168A_ADC_VOL_CHAN_START + 3, 0xd3 },
+	{ PCM3168A_ADC_VOL_CHAN_START + 4, 0xd3 },
+	{ PCM3168A_ADC_VOL_CHAN_START + 5, 0xd3 }
+};
+
+static bool pcm3168a_readable_register(struct device *dev, unsigned int reg)
+{
+	if (reg >= PCM3168A_RST_SMODE)
+		return true;
+	else
+		return false;
+}
+
+static bool pcm3168a_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case PCM3168A_DAC_ZERO:
+	case PCM3168A_ADC_OV:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool pcm3168a_writeable_register(struct device *dev, unsigned int reg)
+{
+	if (reg < PCM3168A_RST_SMODE)
+		return false;
+
+	switch (reg) {
+	case PCM3168A_DAC_ZERO:
+	case PCM3168A_ADC_OV:
+		return false;
+	default:
+		return true;
+	}
+}
+
+const struct regmap_config pcm3168a_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = PCM3168A_ADC_VOL_CHAN_START + 5,
+	.reg_defaults = pcm3168a_reg_default,
+	.num_reg_defaults = ARRAY_SIZE(pcm3168a_reg_default),
+	.readable_reg = pcm3168a_readable_register,
+	.volatile_reg = pcm3168a_volatile_register,
+	.writeable_reg = pcm3168a_writeable_register,
+	.cache_type = REGCACHE_FLAT
+};
+EXPORT_SYMBOL_GPL(pcm3168a_regmap);
+
+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)
+};
+
+int pcm3168a_probe(struct device *dev, struct regmap *regmap)
+{
+	struct pcm3168a_priv *pcm3168a;
+	int ret, i;
+
+	pcm3168a = devm_kzalloc(dev, sizeof(*pcm3168a), GFP_KERNEL);
+	if (pcm3168a == NULL)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, pcm3168a);
+
+	pcm3168a->scki = devm_clk_get(dev, "scki");
+	if (IS_ERR(pcm3168a->scki)) {
+		ret = PTR_ERR(pcm3168a->scki);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "failed to acquire clock 'scki': %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(pcm3168a->scki);
+	if (ret) {
+		dev_err(dev, "Failed to enable mclk: %d\n", ret);
+		return ret;
+	}
+
+	pcm3168a->sysclk = clk_get_rate(pcm3168a->scki);
+
+	for (i = 0; i < ARRAY_SIZE(pcm3168a->supplies); i++)
+		pcm3168a->supplies[i].supply = pcm3168a_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev,
+			ARRAY_SIZE(pcm3168a->supplies), pcm3168a->supplies);
+	if (ret) {
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "failed to request supplies: %d\n", ret);
+		goto err_clk;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies),
+				    pcm3168a->supplies);
+	if (ret) {
+		dev_err(dev, "failed to enable supplies: %d\n", ret);
+		goto err_clk;
+	}
+
+	pcm3168a->regmap = regmap;
+	if (IS_ERR(pcm3168a->regmap)) {
+		ret = PTR_ERR(pcm3168a->regmap);
+		dev_err(dev, "failed to allocate regmap: %d\n", ret);
+		goto err_regulator;
+	}
+
+	ret = pcm3168a_reset(pcm3168a);
+	if (ret) {
+		dev_err(dev, "Failed to reset device: %d\n", ret);
+		goto err_regulator;
+	}
+
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	pm_runtime_idle(dev);
+
+	ret = snd_soc_register_codec(dev, &pcm3168a_driver, pcm3168a_dais,
+			ARRAY_SIZE(pcm3168a_dais));
+	if (ret) {
+		dev_err(dev, "failed to register codec: %d\n", ret);
+		goto err_regulator;
+	}
+
+	return 0;
+
+err_regulator:
+	regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+			pcm3168a->supplies);
+err_clk:
+	clk_disable_unprepare(pcm3168a->scki);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pcm3168a_probe);
+
+void pcm3168a_remove(struct device *dev)
+{
+	struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
+
+	snd_soc_unregister_codec(dev);
+	pm_runtime_disable(dev);
+	regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+				pcm3168a->supplies);
+	clk_disable_unprepare(pcm3168a->scki);
+}
+EXPORT_SYMBOL_GPL(pcm3168a_remove);
+
+#ifdef CONFIG_PM
+static int pcm3168a_rt_resume(struct device *dev)
+{
+	struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(pcm3168a->scki);
+	if (ret) {
+		dev_err(dev, "Failed to enable mclk: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies),
+				    pcm3168a->supplies);
+	if (ret) {
+		dev_err(dev, "Failed to enable supplies: %d\n", ret);
+		goto err_clk;
+	}
+
+	ret = pcm3168a_reset(pcm3168a);
+	if (ret) {
+		dev_err(dev, "Failed to reset device: %d\n", ret);
+		goto err_regulator;
+	}
+
+	regcache_cache_only(pcm3168a->regmap, false);
+
+	regcache_mark_dirty(pcm3168a->regmap);
+
+	ret = regcache_sync(pcm3168a->regmap);
+	if (ret) {
+		dev_err(dev, "Failed to sync regmap: %d\n", ret);
+		goto err_regulator;
+	}
+
+	return 0;
+
+err_regulator:
+	regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+			       pcm3168a->supplies);
+err_clk:
+	clk_disable_unprepare(pcm3168a->scki);
+
+	return ret;
+}
+
+static int pcm3168a_rt_suspend(struct device *dev)
+{
+	struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
+
+	regcache_cache_only(pcm3168a->regmap, true);
+
+	regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
+			       pcm3168a->supplies);
+
+	clk_disable_unprepare(pcm3168a->scki);
+
+	return 0;
+}
+#endif
+
+const struct dev_pm_ops pcm3168a_pm_ops = {
+	SET_RUNTIME_PM_OPS(pcm3168a_rt_suspend, pcm3168a_rt_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(pcm3168a_pm_ops);
+
+MODULE_DESCRIPTION("PCM3168A codec driver");
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3168a.h b/sound/soc/codecs/pcm3168a.h
new file mode 100644
index 0000000..56c8332
--- /dev/null
+++ b/sound/soc/codecs/pcm3168a.h
@@ -0,0 +1,100 @@
+/*
+ * PCM3168A codec driver header
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#ifndef __PCM3168A_H__
+#define __PCM3168A_H__
+
+extern const struct dev_pm_ops pcm3168a_pm_ops;
+extern const struct regmap_config pcm3168a_regmap;
+
+extern int pcm3168a_probe(struct device *dev, struct regmap *regmap);
+extern void pcm3168a_remove(struct device *dev);
+
+#define PCM3168A_RST_SMODE			0x40
+#define PCM3168A_MRST_MASK			0x80
+#define PCM3168A_SRST_MASK			0x40
+#define PCM3168A_DAC_SRDA_SHIFT			0
+#define PCM3168A_DAC_SRDA_MASK			0x3
+
+#define PCM3168A_DAC_PWR_MST_FMT		0x41
+#define PCM3168A_DAC_PSMDA_SHIFT		7
+#define PCM3168A_DAC_PSMDA_MASK			0x80
+#define PCM3168A_DAC_MSDA_SHIFT			4
+#define PCM3168A_DAC_MSDA_MASK			0x70
+#define PCM3168A_DAC_FMT_SHIFT			0
+#define PCM3168A_DAC_FMT_MASK			0xf
+
+#define PCM3168A_DAC_OP_FLT			0x42
+#define PCM3168A_DAC_OPEDA_SHIFT		4
+#define PCM3168A_DAC_OPEDA_MASK			0xf0
+#define PCM3168A_DAC_FLT_SHIFT			0
+#define PCM3168A_DAC_FLT_MASK			0xf
+
+#define PCM3168A_DAC_INV			0x43
+
+#define PCM3168A_DAC_MUTE			0x44
+
+#define PCM3168A_DAC_ZERO			0x45
+
+#define PCM3168A_DAC_ATT_DEMP_ZF		0x46
+#define PCM3168A_DAC_ATMDDA_MASK		0x80
+#define PCM3168A_DAC_ATMDDA_SHIFT		7
+#define PCM3168A_DAC_ATSPDA_MASK		0x40
+#define PCM3168A_DAC_ATSPDA_SHIFT		6
+#define PCM3168A_DAC_DEMP_SHIFT			4
+#define PCM3168A_DAC_DEMP_MASK			0x30
+#define PCM3168A_DAC_AZRO_SHIFT			1
+#define PCM3168A_DAC_AZRO_MASK			0xe
+#define PCM3168A_DAC_ZREV_MASK			0x1
+#define PCM3168A_DAC_ZREV_SHIFT			0
+
+#define PCM3168A_DAC_VOL_MASTER			0x47
+
+#define PCM3168A_DAC_VOL_CHAN_START		0x48
+
+#define PCM3168A_ADC_SMODE			0x50
+#define PCM3168A_ADC_SRAD_SHIFT			0
+#define PCM3168A_ADC_SRAD_MASK			0x3
+
+#define PCM3168A_ADC_MST_FMT			0x51
+#define PCM3168A_ADC_MSAD_SHIFT			4
+#define PCM3168A_ADC_MSAD_MASK			0x70
+#define PCM3168A_ADC_FMTAD_SHIFT		0
+#define PCM3168A_ADC_FMTAD_MASK			0x7
+
+#define PCM3168A_ADC_PWR_HPFB			0x52
+#define PCM3168A_ADC_PSVAD_SHIFT		4
+#define PCM3168A_ADC_PSVAD_MASK			0x70
+#define PCM3168A_ADC_BYP_SHIFT			0
+#define PCM3168A_ADC_BYP_MASK			0x7
+
+#define PCM3168A_ADC_SEAD			0x53
+
+#define PCM3168A_ADC_INV			0x54
+
+#define PCM3168A_ADC_MUTE			0x55
+
+#define PCM3168A_ADC_OV				0x56
+
+#define PCM3168A_ADC_ATT_OVF			0x57
+#define PCM3168A_ADC_ATMDAD_MASK		0x80
+#define PCM3168A_ADC_ATMDAD_SHIFT		7
+#define PCM3168A_ADC_ATSPAD_MASK		0x40
+#define PCM3168A_ADC_ATSPAD_SHIFT		6
+#define PCM3168A_ADC_OVFP_MASK			0x1
+#define PCM3168A_ADC_OVFP_SHIFT			0
+
+#define PCM3168A_ADC_VOL_MASTER			0x58
+
+#define PCM3168A_ADC_VOL_CHAN_START		0x59
+
+#endif
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index af2ed77..bc08f0c 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -1114,6 +1114,12 @@
 			DMI_MATCH(DMI_BOARD_NAME, "Wilson Beach SDS")
 		}
 	},
+	{
+		.ident = "Intel Skylake RVP",
+		.matches = {
+			DMI_MATCH(DMI_PRODUCT_NAME, "Skylake Client platform")
+		}
+	},
 	{ }
 };
 
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index b3f795c..30c6de6 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -855,8 +855,6 @@
 		snd_soc_update_bits(codec,
 			RT298_I2S_CTRL2, 0x0100, 0x0100);
 		snd_soc_update_bits(codec,
-			RT298_PLL_CTRL, 0x4, 0x4);
-		snd_soc_update_bits(codec,
 			RT298_PLL_CTRL1, 0x20, 0x0);
 	}
 
diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c
new file mode 100644
index 0000000..1c10d8e
--- /dev/null
+++ b/sound/soc/codecs/rt5616.c
@@ -0,0 +1,1381 @@
+/*
+ * rt5616.c  --  RT5616 ALSA SoC audio codec driver
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@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 <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 "rt5616.h"
+
+#define RT5616_PR_RANGE_BASE (0xff + 1)
+#define RT5616_PR_SPACING 0x100
+
+#define RT5616_PR_BASE (RT5616_PR_RANGE_BASE + (0 * RT5616_PR_SPACING))
+
+static const struct regmap_range_cfg rt5616_ranges[] = {
+	{
+		.name = "PR",
+		.range_min = RT5616_PR_BASE,
+		.range_max = RT5616_PR_BASE + 0xf8,
+		.selector_reg = RT5616_PRIV_INDEX,
+		.selector_mask = 0xff,
+		.selector_shift = 0x0,
+		.window_start = RT5616_PRIV_DATA,
+		.window_len = 0x1,
+	},
+};
+
+static const struct reg_sequence init_list[] = {
+	{RT5616_PR_BASE + 0x3d,	0x3e00},
+	{RT5616_PR_BASE + 0x25,	0x6110},
+	{RT5616_PR_BASE + 0x20,	0x611f},
+	{RT5616_PR_BASE + 0x21,	0x4040},
+	{RT5616_PR_BASE + 0x23,	0x0004},
+};
+#define RT5616_INIT_REG_LEN ARRAY_SIZE(init_list)
+
+static const struct reg_default rt5616_reg[] = {
+	{ 0x00, 0x0021 },
+	{ 0x02, 0xc8c8 },
+	{ 0x03, 0xc8c8 },
+	{ 0x05, 0x0000 },
+	{ 0x0d, 0x0000 },
+	{ 0x0f, 0x0808 },
+	{ 0x19, 0xafaf },
+	{ 0x1c, 0x2f2f },
+	{ 0x1e, 0x0000 },
+	{ 0x27, 0x7860 },
+	{ 0x29, 0x8080 },
+	{ 0x2a, 0x5252 },
+	{ 0x3b, 0x0000 },
+	{ 0x3c, 0x006f },
+	{ 0x3d, 0x0000 },
+	{ 0x3e, 0x006f },
+	{ 0x45, 0x6000 },
+	{ 0x4d, 0x0000 },
+	{ 0x4e, 0x0000 },
+	{ 0x4f, 0x0279 },
+	{ 0x50, 0x0000 },
+	{ 0x51, 0x0000 },
+	{ 0x52, 0x0279 },
+	{ 0x53, 0xf000 },
+	{ 0x61, 0x0000 },
+	{ 0x62, 0x0000 },
+	{ 0x63, 0x00c0 },
+	{ 0x64, 0x0000 },
+	{ 0x65, 0x0000 },
+	{ 0x66, 0x0000 },
+	{ 0x70, 0x8000 },
+	{ 0x73, 0x1104 },
+	{ 0x74, 0x0c00 },
+	{ 0x80, 0x0000 },
+	{ 0x81, 0x0000 },
+	{ 0x82, 0x0000 },
+	{ 0x8b, 0x0600 },
+	{ 0x8e, 0x0004 },
+	{ 0x8f, 0x1100 },
+	{ 0x90, 0x0000 },
+	{ 0x91, 0x0000 },
+	{ 0x92, 0x0000 },
+	{ 0x93, 0x2000 },
+	{ 0x94, 0x0200 },
+	{ 0x95, 0x0000 },
+	{ 0xb0, 0x2080 },
+	{ 0xb1, 0x0000 },
+	{ 0xb2, 0x0000 },
+	{ 0xb4, 0x2206 },
+	{ 0xb5, 0x1f00 },
+	{ 0xb6, 0x0000 },
+	{ 0xb7, 0x0000 },
+	{ 0xbb, 0x0000 },
+	{ 0xbc, 0x0000 },
+	{ 0xbd, 0x0000 },
+	{ 0xbe, 0x0000 },
+	{ 0xbf, 0x0000 },
+	{ 0xc0, 0x0100 },
+	{ 0xc1, 0x0000 },
+	{ 0xc2, 0x0000 },
+	{ 0xc8, 0x0000 },
+	{ 0xc9, 0x0000 },
+	{ 0xca, 0x0000 },
+	{ 0xcb, 0x0000 },
+	{ 0xcc, 0x0000 },
+	{ 0xcd, 0x0000 },
+	{ 0xce, 0x0000 },
+	{ 0xcf, 0x0013 },
+	{ 0xd0, 0x0680 },
+	{ 0xd1, 0x1c17 },
+	{ 0xd3, 0xb320 },
+	{ 0xd4, 0x0000 },
+	{ 0xd6, 0x0000 },
+	{ 0xd7, 0x0000 },
+	{ 0xd9, 0x0809 },
+	{ 0xda, 0x0000 },
+	{ 0xfa, 0x0010 },
+	{ 0xfb, 0x0000 },
+	{ 0xfc, 0x0000 },
+	{ 0xfe, 0x10ec },
+	{ 0xff, 0x6281 },
+};
+
+struct rt5616_priv {
+	struct snd_soc_codec *codec;
+	struct delayed_work patch_work;
+	struct regmap *regmap;
+
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5616_AIFS];
+	int bclk[RT5616_AIFS];
+	int master[RT5616_AIFS];
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+
+};
+
+static bool rt5616_volatile_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5616_ranges); i++) {
+		if (reg >= rt5616_ranges[i].range_min &&
+			reg <= rt5616_ranges[i].range_max) {
+			return true;
+		}
+	}
+
+	switch (reg) {
+	case RT5616_RESET:
+	case RT5616_PRIV_DATA:
+	case RT5616_EQ_CTRL1:
+	case RT5616_DRC_AGC_1:
+	case RT5616_IRQ_CTRL2:
+	case RT5616_INT_IRQ_ST:
+	case RT5616_PGM_REG_ARR1:
+	case RT5616_PGM_REG_ARR3:
+	case RT5616_VENDOR_ID:
+	case RT5616_DEVICE_ID:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5616_readable_register(struct device *dev, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rt5616_ranges); i++) {
+		if (reg >= rt5616_ranges[i].range_min &&
+			reg <= rt5616_ranges[i].range_max) {
+			return true;
+		}
+	}
+
+	switch (reg) {
+	case RT5616_RESET:
+	case RT5616_VERSION_ID:
+	case RT5616_VENDOR_ID:
+	case RT5616_DEVICE_ID:
+	case RT5616_HP_VOL:
+	case RT5616_LOUT_CTRL1:
+	case RT5616_LOUT_CTRL2:
+	case RT5616_IN1_IN2:
+	case RT5616_INL1_INR1_VOL:
+	case RT5616_DAC1_DIG_VOL:
+	case RT5616_ADC_DIG_VOL:
+	case RT5616_ADC_BST_VOL:
+	case RT5616_STO1_ADC_MIXER:
+	case RT5616_AD_DA_MIXER:
+	case RT5616_STO_DAC_MIXER:
+	case RT5616_REC_L1_MIXER:
+	case RT5616_REC_L2_MIXER:
+	case RT5616_REC_R1_MIXER:
+	case RT5616_REC_R2_MIXER:
+	case RT5616_HPO_MIXER:
+	case RT5616_OUT_L1_MIXER:
+	case RT5616_OUT_L2_MIXER:
+	case RT5616_OUT_L3_MIXER:
+	case RT5616_OUT_R1_MIXER:
+	case RT5616_OUT_R2_MIXER:
+	case RT5616_OUT_R3_MIXER:
+	case RT5616_LOUT_MIXER:
+	case RT5616_PWR_DIG1:
+	case RT5616_PWR_DIG2:
+	case RT5616_PWR_ANLG1:
+	case RT5616_PWR_ANLG2:
+	case RT5616_PWR_MIXER:
+	case RT5616_PWR_VOL:
+	case RT5616_PRIV_INDEX:
+	case RT5616_PRIV_DATA:
+	case RT5616_I2S1_SDP:
+	case RT5616_ADDA_CLK1:
+	case RT5616_ADDA_CLK2:
+	case RT5616_GLB_CLK:
+	case RT5616_PLL_CTRL1:
+	case RT5616_PLL_CTRL2:
+	case RT5616_HP_OVCD:
+	case RT5616_DEPOP_M1:
+	case RT5616_DEPOP_M2:
+	case RT5616_DEPOP_M3:
+	case RT5616_CHARGE_PUMP:
+	case RT5616_PV_DET_SPK_G:
+	case RT5616_MICBIAS:
+	case RT5616_A_JD_CTL1:
+	case RT5616_A_JD_CTL2:
+	case RT5616_EQ_CTRL1:
+	case RT5616_EQ_CTRL2:
+	case RT5616_WIND_FILTER:
+	case RT5616_DRC_AGC_1:
+	case RT5616_DRC_AGC_2:
+	case RT5616_DRC_AGC_3:
+	case RT5616_SVOL_ZC:
+	case RT5616_JD_CTRL1:
+	case RT5616_JD_CTRL2:
+	case RT5616_IRQ_CTRL1:
+	case RT5616_IRQ_CTRL2:
+	case RT5616_INT_IRQ_ST:
+	case RT5616_GPIO_CTRL1:
+	case RT5616_GPIO_CTRL2:
+	case RT5616_GPIO_CTRL3:
+	case RT5616_PGM_REG_ARR1:
+	case RT5616_PGM_REG_ARR2:
+	case RT5616_PGM_REG_ARR3:
+	case RT5616_PGM_REG_ARR4:
+	case RT5616_PGM_REG_ARR5:
+	case RT5616_SCB_FUNC:
+	case RT5616_SCB_CTRL:
+	case RT5616_BASE_BACK:
+	case RT5616_MP3_PLUS1:
+	case RT5616_MP3_PLUS2:
+	case RT5616_ADJ_HPF_CTRL1:
+	case RT5616_ADJ_HPF_CTRL2:
+	case RT5616_HP_CALIB_AMP_DET:
+	case RT5616_HP_CALIB2:
+	case RT5616_SV_ZCD1:
+	case RT5616_SV_ZCD2:
+	case RT5616_D_MISC:
+	case RT5616_DUMMY2:
+	case RT5616_DUMMY3:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static unsigned int bst_tlv[] = {
+	TLV_DB_RANGE_HEAD(7),
+	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),
+};
+
+static const struct snd_kcontrol_new rt5616_snd_controls[] = {
+	/* Headphone Output Volume */
+	SOC_DOUBLE("HP Playback Switch", RT5616_HP_VOL,
+		RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("HP Playback Volume", RT5616_HP_VOL,
+		RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv),
+	/* OUTPUT Control */
+	SOC_DOUBLE("OUT Playback Switch", RT5616_LOUT_CTRL1,
+		RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE("OUT Channel Switch", RT5616_LOUT_CTRL1,
+		RT5616_VOL_L_SFT, RT5616_VOL_R_SFT, 1, 1),
+	SOC_DOUBLE_TLV("OUT Playback Volume", RT5616_LOUT_CTRL1,
+		RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+	/* DAC Digital Volume */
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5616_DAC1_DIG_VOL,
+			RT5616_L_VOL_SFT, RT5616_R_VOL_SFT,
+			175, 0, dac_vol_tlv),
+	/* IN1/IN2 Control */
+	SOC_SINGLE_TLV("IN1 Boost Volume", RT5616_IN1_IN2,
+		RT5616_BST_SFT1, 8, 0, bst_tlv),
+	SOC_SINGLE_TLV("IN2 Boost Volume", RT5616_IN1_IN2,
+		RT5616_BST_SFT2, 8, 0, bst_tlv),
+	/* INL/INR Volume Control */
+	SOC_DOUBLE_TLV("IN Capture Volume", RT5616_INL1_INR1_VOL,
+			RT5616_INL_VOL_SFT, RT5616_INR_VOL_SFT,
+			31, 1, in_vol_tlv),
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("ADC Capture Switch", RT5616_ADC_DIG_VOL,
+		RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("ADC Capture Volume", RT5616_ADC_DIG_VOL,
+			RT5616_L_VOL_SFT, RT5616_R_VOL_SFT,
+			127, 0, adc_vol_tlv),
+
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("ADC Boost Volume", RT5616_ADC_BST_VOL,
+			RT5616_ADC_L_BST_SFT, RT5616_ADC_R_BST_SFT,
+			3, 0, adc_bst_tlv),
+};
+
+static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink)
+{
+	unsigned int val;
+
+	val = snd_soc_read(snd_soc_dapm_to_codec(source->dapm), RT5616_GLB_CLK);
+	val &= RT5616_SCLK_SRC_MASK;
+	if (val == RT5616_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5616_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5616_STO1_ADC_MIXER,
+			RT5616_M_STO1_ADC_L1_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5616_STO1_ADC_MIXER,
+			RT5616_M_STO1_ADC_R1_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5616_AD_DA_MIXER,
+			RT5616_M_ADCMIX_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INF1 Switch", RT5616_AD_DA_MIXER,
+			RT5616_M_IF1_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5616_AD_DA_MIXER,
+			RT5616_M_ADCMIX_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INF1 Switch", RT5616_AD_DA_MIXER,
+			RT5616_M_IF1_DAC_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_sto_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_STO_DAC_MIXER,
+			RT5616_M_DAC_L1_MIXL_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_STO_DAC_MIXER,
+			RT5616_M_DAC_R1_MIXL_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_sto_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_STO_DAC_MIXER,
+			RT5616_M_DAC_R1_MIXR_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_STO_DAC_MIXER,
+			RT5616_M_DAC_L1_MIXR_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5616_rec_l_mix[] = {
+	SOC_DAPM_SINGLE("INL1 Switch", RT5616_REC_L2_MIXER,
+			RT5616_M_IN1_L_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5616_REC_L2_MIXER,
+			RT5616_M_BST2_RM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5616_REC_L2_MIXER,
+			RT5616_M_BST1_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_rec_r_mix[] = {
+	SOC_DAPM_SINGLE("INR1 Switch", RT5616_REC_R2_MIXER,
+			RT5616_M_IN1_R_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5616_REC_R2_MIXER,
+			RT5616_M_BST2_RM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5616_REC_R2_MIXER,
+			RT5616_M_BST1_RM_R_SFT, 1, 1),
+};
+
+/* Analog Output Mixer */
+
+static const struct snd_kcontrol_new rt5616_out_l_mix[] = {
+	SOC_DAPM_SINGLE("BST1 Switch", RT5616_OUT_L3_MIXER,
+			RT5616_M_BST1_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5616_OUT_L3_MIXER,
+			RT5616_M_BST2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL1 Switch", RT5616_OUT_L3_MIXER,
+			RT5616_M_IN1_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("REC MIXL Switch", RT5616_OUT_L3_MIXER,
+			RT5616_M_RM_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_OUT_L3_MIXER,
+			RT5616_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_out_r_mix[] = {
+	SOC_DAPM_SINGLE("BST2 Switch", RT5616_OUT_R3_MIXER,
+			RT5616_M_BST2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5616_OUT_R3_MIXER,
+			RT5616_M_BST1_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR1 Switch", RT5616_OUT_R3_MIXER,
+			RT5616_M_IN1_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("REC MIXR Switch", RT5616_OUT_R3_MIXER,
+			RT5616_M_RM_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_OUT_R3_MIXER,
+			RT5616_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_hpo_mix[] = {
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5616_HPO_MIXER,
+			RT5616_M_DAC1_HM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("HPVOL Switch", RT5616_HPO_MIXER,
+			RT5616_M_HPVOL_HM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5616_lout_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_LOUT_MIXER,
+			RT5616_M_DAC_L1_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_LOUT_MIXER,
+			RT5616_M_DAC_R1_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL L Switch", RT5616_LOUT_MIXER,
+			RT5616_M_OV_L_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL R Switch", RT5616_LOUT_MIXER,
+			RT5616_M_OV_R_LM_SFT, 1, 1),
+};
+
+static int rt5616_adc_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, RT5616_ADC_DIG_VOL,
+				RT5616_L_MUTE | RT5616_R_MUTE, 0);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, RT5616_ADC_DIG_VOL,
+				RT5616_L_MUTE | RT5616_R_MUTE,
+				RT5616_L_MUTE | RT5616_R_MUTE);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5616_charge_pump_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:
+		/* depop parameters */
+		snd_soc_update_bits(codec, RT5616_DEPOP_M2,
+			RT5616_DEPOP_MASK, RT5616_DEPOP_MAN);
+		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+			RT5616_HP_CP_MASK | RT5616_HP_SG_MASK |
+			RT5616_HP_CB_MASK, RT5616_HP_CP_PU |
+			RT5616_HP_SG_DIS | RT5616_HP_CB_PU);
+		snd_soc_write(codec, RT5616_PR_BASE +
+			RT5616_HP_DCC_INT1, 0x9f00);
+		/* headphone amp power on */
+		snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+			RT5616_PWR_FV1 | RT5616_PWR_FV2, 0);
+		snd_soc_update_bits(codec, RT5616_PWR_VOL,
+			RT5616_PWR_HV_L | RT5616_PWR_HV_R,
+			RT5616_PWR_HV_L | RT5616_PWR_HV_R);
+		snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+			RT5616_PWR_HP_L | RT5616_PWR_HP_R |
+			RT5616_PWR_HA, RT5616_PWR_HP_L |
+			RT5616_PWR_HP_R | RT5616_PWR_HA);
+		msleep(50);
+		snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+			RT5616_PWR_FV1 | RT5616_PWR_FV2,
+			RT5616_PWR_FV1 | RT5616_PWR_FV2);
+
+		snd_soc_update_bits(codec, RT5616_CHARGE_PUMP,
+			RT5616_PM_HP_MASK, RT5616_PM_HP_HV);
+		snd_soc_update_bits(codec, RT5616_PR_BASE +
+			RT5616_CHOP_DAC_ADC, 0x0200, 0x0200);
+		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+			RT5616_HP_CO_MASK | RT5616_HP_SG_MASK,
+			RT5616_HP_CO_EN | RT5616_HP_SG_EN);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, RT5616_PR_BASE +
+			RT5616_CHOP_DAC_ADC, 0x0200, 0x0);
+		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+			RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK |
+			RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS |
+			RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS);
+		/* headphone amp power down */
+		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+			RT5616_SMT_TRIG_MASK | RT5616_HP_CD_PD_MASK |
+			RT5616_HP_CO_MASK | RT5616_HP_CP_MASK |
+			RT5616_HP_SG_MASK | RT5616_HP_CB_MASK,
+			RT5616_SMT_TRIG_DIS | RT5616_HP_CD_PD_EN |
+			RT5616_HP_CO_DIS | RT5616_HP_CP_PD |
+			RT5616_HP_SG_EN | RT5616_HP_CB_PD);
+		snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+			RT5616_PWR_HP_L | RT5616_PWR_HP_R |
+			RT5616_PWR_HA, 0);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5616_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);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* headphone unmute sequence */
+		snd_soc_update_bits(codec, RT5616_DEPOP_M3,
+			RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK |
+			RT5616_CP_FQ3_MASK,
+			(RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ1_SFT) |
+			(RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT) |
+			(RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ3_SFT));
+		snd_soc_write(codec, RT5616_PR_BASE +
+			RT5616_MAMP_INT_REG2, 0xfc00);
+		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+			RT5616_SMT_TRIG_MASK, RT5616_SMT_TRIG_EN);
+		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+			RT5616_RSTN_MASK, RT5616_RSTN_EN);
+		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+			RT5616_RSTN_MASK | RT5616_HP_L_SMT_MASK |
+			RT5616_HP_R_SMT_MASK, RT5616_RSTN_DIS |
+			RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN);
+		snd_soc_update_bits(codec, RT5616_HP_VOL,
+			RT5616_L_MUTE | RT5616_R_MUTE, 0);
+		msleep(100);
+		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+			RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK |
+			RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS |
+			RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS);
+		msleep(20);
+		snd_soc_update_bits(codec, RT5616_HP_CALIB_AMP_DET,
+			RT5616_HPD_PS_MASK, RT5616_HPD_PS_EN);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		/* headphone mute sequence */
+		snd_soc_update_bits(codec, RT5616_DEPOP_M3,
+			RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK |
+			RT5616_CP_FQ3_MASK,
+			(RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ1_SFT) |
+			(RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT) |
+			(RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ3_SFT));
+		snd_soc_write(codec, RT5616_PR_BASE +
+			RT5616_MAMP_INT_REG2, 0xfc00);
+		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+			RT5616_HP_SG_MASK, RT5616_HP_SG_EN);
+		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+			RT5616_RSTP_MASK, RT5616_RSTP_EN);
+		snd_soc_update_bits(codec, RT5616_DEPOP_M1,
+			RT5616_RSTP_MASK | RT5616_HP_L_SMT_MASK |
+			RT5616_HP_R_SMT_MASK, RT5616_RSTP_DIS |
+			RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN);
+		snd_soc_update_bits(codec, RT5616_HP_CALIB_AMP_DET,
+			RT5616_HPD_PS_MASK, RT5616_HPD_PS_DIS);
+		msleep(90);
+		snd_soc_update_bits(codec, RT5616_HP_VOL,
+			RT5616_L_MUTE | RT5616_R_MUTE,
+			RT5616_L_MUTE | RT5616_R_MUTE);
+		msleep(30);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5616_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, RT5616_PWR_ANLG1,
+			RT5616_PWR_LM, RT5616_PWR_LM);
+		snd_soc_update_bits(codec, RT5616_LOUT_CTRL1,
+			RT5616_L_MUTE | RT5616_R_MUTE, 0);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, RT5616_LOUT_CTRL1,
+			RT5616_L_MUTE | RT5616_R_MUTE,
+			RT5616_L_MUTE | RT5616_R_MUTE);
+		snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+			RT5616_PWR_LM, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5616_bst1_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, RT5616_PWR_ANLG2,
+			RT5616_PWR_BST1_OP2, RT5616_PWR_BST1_OP2);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, RT5616_PWR_ANLG2,
+			RT5616_PWR_BST1_OP2, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5616_bst2_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, RT5616_PWR_ANLG2,
+			RT5616_PWR_BST2_OP2, RT5616_PWR_BST2_OP2);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, RT5616_PWR_ANLG2,
+			RT5616_PWR_BST2_OP2, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5616_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("PLL1", RT5616_PWR_ANLG2,
+			RT5616_PWR_PLL_BIT, 0, NULL, 0),
+	/* Input Side */
+	/* micbias */
+	SND_SOC_DAPM_SUPPLY("LDO", RT5616_PWR_ANLG1,
+			RT5616_PWR_LDO_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("micbias1", RT5616_PWR_ANLG2,
+			RT5616_PWR_MB1_BIT, 0, NULL, 0),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN2N"),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA_E("BST1", RT5616_PWR_ANLG2,
+		RT5616_PWR_BST1_BIT, 0, NULL, 0, rt5616_bst1_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_E("BST2", RT5616_PWR_ANLG2,
+		RT5616_PWR_BST2_BIT, 0, NULL, 0, rt5616_bst2_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	/* Input Volume */
+	SND_SOC_DAPM_PGA("INL1 VOL", RT5616_PWR_VOL,
+		RT5616_PWR_IN1_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR1 VOL", RT5616_PWR_VOL,
+		RT5616_PWR_IN1_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INL2 VOL", RT5616_PWR_VOL,
+		RT5616_PWR_IN2_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR2 VOL", RT5616_PWR_VOL,
+		RT5616_PWR_IN2_R_BIT, 0, NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIXL", RT5616_PWR_MIXER, RT5616_PWR_RM_L_BIT, 0,
+			rt5616_rec_l_mix, ARRAY_SIZE(rt5616_rec_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIXR", RT5616_PWR_MIXER, RT5616_PWR_RM_R_BIT, 0,
+			rt5616_rec_r_mix, ARRAY_SIZE(rt5616_rec_r_mix)),
+	/* ADCs */
+	SND_SOC_DAPM_ADC_E("ADC L", NULL, RT5616_PWR_DIG1,
+		RT5616_PWR_ADC_L_BIT, 0, rt5616_adc_event,
+		SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_ADC_E("ADC R", NULL, RT5616_PWR_DIG1,
+		RT5616_PWR_ADC_R_BIT, 0, rt5616_adc_event,
+		SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("stereo1 filter", RT5616_PWR_DIG2,
+		RT5616_PWR_ADC_STO1_F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5616_sto1_adc_l_mix, ARRAY_SIZE(rt5616_sto1_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5616_sto1_adc_r_mix, ARRAY_SIZE(rt5616_sto1_adc_r_mix)),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1", RT5616_PWR_DIG1,
+		RT5616_PWR_I2S1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 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),
+
+	/* Digital Interface Select */
+
+	/* 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),
+
+	/* Audio DSP */
+	SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Output Side */
+	/* DAC mixer before sound effect  */
+	SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5616_dac_l_mix, ARRAY_SIZE(rt5616_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5616_dac_r_mix, ARRAY_SIZE(rt5616_dac_r_mix)),
+
+	SND_SOC_DAPM_SUPPLY("Stero1 DAC Power", RT5616_PWR_DIG2,
+			RT5616_PWR_DAC_STO1_F_BIT, 0, NULL, 0),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5616_sto_dac_l_mix, ARRAY_SIZE(rt5616_sto_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5616_sto_dac_r_mix, ARRAY_SIZE(rt5616_sto_dac_r_mix)),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC L1", NULL, RT5616_PWR_DIG1,
+			RT5616_PWR_DAC_L1_BIT, 0),
+	SND_SOC_DAPM_DAC("DAC R1", NULL, RT5616_PWR_DIG1,
+			RT5616_PWR_DAC_R1_BIT, 0),
+	/* OUT Mixer */
+	SND_SOC_DAPM_MIXER("OUT MIXL", RT5616_PWR_MIXER, RT5616_PWR_OM_L_BIT,
+		0, rt5616_out_l_mix, ARRAY_SIZE(rt5616_out_l_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXR", RT5616_PWR_MIXER, RT5616_PWR_OM_R_BIT,
+		0, rt5616_out_r_mix, ARRAY_SIZE(rt5616_out_r_mix)),
+	/* Output Volume */
+	SND_SOC_DAPM_PGA("OUTVOL L", RT5616_PWR_VOL,
+		RT5616_PWR_OV_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OUTVOL R", RT5616_PWR_VOL,
+		RT5616_PWR_OV_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HPOVOL L", RT5616_PWR_VOL,
+		RT5616_PWR_HV_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HPOVOL R", RT5616_PWR_VOL,
+		RT5616_PWR_HV_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DAC 2", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HPOVOL", SND_SOC_NOPM,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INL1", RT5616_PWR_VOL,
+		RT5616_PWR_IN1_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR1", RT5616_PWR_VOL,
+		RT5616_PWR_IN1_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INL2", RT5616_PWR_VOL,
+		RT5616_PWR_IN2_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR2", RT5616_PWR_VOL,
+		RT5616_PWR_IN2_R_BIT, 0, NULL, 0),
+	/* HPO/LOUT/Mono Mixer */
+	SND_SOC_DAPM_MIXER("HPO MIX", SND_SOC_NOPM, 0, 0,
+		rt5616_hpo_mix, ARRAY_SIZE(rt5616_hpo_mix)),
+	SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0,
+		rt5616_lout_mix, ARRAY_SIZE(rt5616_lout_mix)),
+
+	SND_SOC_DAPM_PGA_S("HP amp", 1, SND_SOC_NOPM, 0, 0,
+		rt5616_hp_event, SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("LOUT amp", 1, SND_SOC_NOPM, 0, 0,
+		rt5616_lout_event, SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, SND_SOC_NOPM, 0, 0,
+		rt5616_charge_pump_event, SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+	SND_SOC_DAPM_OUTPUT("LOUTL"),
+	SND_SOC_DAPM_OUTPUT("LOUTR"),
+};
+
+static const struct snd_soc_dapm_route rt5616_dapm_routes[] = {
+	{"IN1P", NULL, "LDO"},
+	{"IN2P", NULL, "LDO"},
+
+	{"IN1P", NULL, "MIC1"},
+	{"IN2P", NULL, "MIC2"},
+	{"IN2N", NULL, "MIC2"},
+
+	{"BST1", NULL, "IN1P"},
+	{"BST2", NULL, "IN2P"},
+	{"BST2", NULL, "IN2N"},
+	{"BST1", NULL, "micbias1"},
+	{"BST2", NULL, "micbias1"},
+
+	{"INL1 VOL", NULL, "IN2P"},
+	{"INR1 VOL", NULL, "IN2N"},
+
+	{"RECMIXL", "INL1 Switch", "INL1 VOL"},
+	{"RECMIXL", "BST2 Switch", "BST2"},
+	{"RECMIXL", "BST1 Switch", "BST1"},
+
+	{"RECMIXR", "INR1 Switch", "INR1 VOL"},
+	{"RECMIXR", "BST2 Switch", "BST2"},
+	{"RECMIXR", "BST1 Switch", "BST1"},
+
+	{"ADC L", NULL, "RECMIXL"},
+	{"ADC R", NULL, "RECMIXR"},
+
+	{"Stereo1 ADC MIXL", "ADC1 Switch", "ADC L"},
+	{"Stereo1 ADC MIXL", NULL, "stereo1 filter"},
+	{"stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll},
+
+	{"Stereo1 ADC MIXR", "ADC1 Switch", "ADC R"},
+	{"Stereo1 ADC MIXR", NULL, "stereo1 filter"},
+	{"stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll},
+
+	{"IF1 ADC1", NULL, "Stereo1 ADC MIXL"},
+	{"IF1 ADC1", NULL, "Stereo1 ADC MIXR"},
+	{"IF1 ADC1", NULL, "I2S1"},
+
+	{"AIF1TX", NULL, "IF1 ADC1"},
+
+	{"IF1 DAC", NULL, "AIF1RX"},
+	{"IF1 DAC", NULL, "I2S1"},
+
+	{"IF1 DAC1 L", NULL, "IF1 DAC"},
+	{"IF1 DAC1 R", NULL, "IF1 DAC"},
+
+	{"DAC MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"},
+	{"DAC MIXL", "INF1 Switch", "IF1 DAC1 L"},
+	{"DAC MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"},
+	{"DAC MIXR", "INF1 Switch", "IF1 DAC1 R"},
+
+	{"Audio DSP", NULL, "DAC MIXL"},
+	{"Audio DSP", NULL, "DAC MIXR"},
+
+	{"Stereo DAC MIXL", "DAC L1 Switch", "Audio DSP"},
+	{"Stereo DAC MIXL", "DAC R1 Switch", "DAC MIXR"},
+	{"Stereo DAC MIXL", NULL, "Stero1 DAC Power"},
+	{"Stereo DAC MIXR", "DAC R1 Switch", "Audio DSP"},
+	{"Stereo DAC MIXR", "DAC L1 Switch", "DAC MIXL"},
+	{"Stereo DAC MIXR", NULL, "Stero1 DAC Power"},
+
+	{"DAC L1", NULL, "Stereo DAC MIXL"},
+	{"DAC L1", NULL, "PLL1", is_sys_clk_from_pll},
+	{"DAC R1", NULL, "Stereo DAC MIXR"},
+	{"DAC R1", NULL, "PLL1", is_sys_clk_from_pll},
+
+	{"OUT MIXL", "BST1 Switch", "BST1"},
+	{"OUT MIXL", "BST2 Switch", "BST2"},
+	{"OUT MIXL", "INL1 Switch", "INL1 VOL"},
+	{"OUT MIXL", "REC MIXL Switch", "RECMIXL"},
+	{"OUT MIXL", "DAC L1 Switch", "DAC L1"},
+
+	{"OUT MIXR", "BST2 Switch", "BST2"},
+	{"OUT MIXR", "BST1 Switch", "BST1"},
+	{"OUT MIXR", "INR1 Switch", "INR1 VOL"},
+	{"OUT MIXR", "REC MIXR Switch", "RECMIXR"},
+	{"OUT MIXR", "DAC R1 Switch", "DAC R1"},
+
+	{"HPOVOL L", NULL, "OUT MIXL"},
+	{"HPOVOL R", NULL, "OUT MIXR"},
+	{"OUTVOL L", NULL, "OUT MIXL"},
+	{"OUTVOL R", NULL, "OUT MIXR"},
+
+	{"DAC 1", NULL, "DAC L1"},
+	{"DAC 1", NULL, "DAC R1"},
+	{"HPOVOL", NULL, "HPOVOL L"},
+	{"HPOVOL", NULL, "HPOVOL R"},
+	{"HPO MIX", "DAC1 Switch", "DAC 1"},
+	{"HPO MIX", "HPVOL Switch", "HPOVOL"},
+
+	{"LOUT MIX", "DAC L1 Switch", "DAC L1"},
+	{"LOUT MIX", "DAC R1 Switch", "DAC R1"},
+	{"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"},
+	{"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"},
+
+	{"HP amp", NULL, "HPO MIX"},
+	{"HP amp", NULL, "Charge Pump"},
+	{"HPOL", NULL, "HP amp"},
+	{"HPOR", NULL, "HP amp"},
+
+	{"LOUT amp", NULL, "LOUT MIX"},
+	{"LOUT amp", NULL, "Charge Pump"},
+	{"LOUTL", NULL, "LOUT amp"},
+	{"LOUTR", NULL, "LOUT amp"},
+
+};
+
+static int rt5616_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+	unsigned int val_len = 0, val_clk, mask_clk;
+	int pre_div, bclk_ms, frame_size;
+
+	rt5616->lrck[dai->id] = params_rate(params);
+
+	pre_div = rl6231_get_clk_info(rt5616->sysclk, rt5616->lrck[dai->id]);
+
+	if (pre_div < 0) {
+		dev_err(codec->dev, "Unsupported clock setting\n");
+		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 -EINVAL;
+	}
+	bclk_ms = frame_size > 32 ? 1 : 0;
+	rt5616->bclk[dai->id] = rt5616->lrck[dai->id] * (32 << bclk_ms);
+
+	dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+		rt5616->bclk[dai->id], rt5616->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_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		val_len |= RT5616_I2S_DL_20;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		val_len |= RT5616_I2S_DL_24;
+		break;
+	case SNDRV_PCM_FORMAT_S8:
+		val_len |= RT5616_I2S_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mask_clk = RT5616_I2S_PD1_MASK;
+	val_clk = pre_div << RT5616_I2S_PD1_SFT;
+	snd_soc_update_bits(codec, RT5616_I2S1_SDP,
+		RT5616_I2S_DL_MASK, val_len);
+	snd_soc_update_bits(codec, RT5616_ADDA_CLK1, mask_clk, val_clk);
+
+
+	return 0;
+}
+
+static int rt5616_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+	unsigned int reg_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5616->master[dai->id] = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT5616_I2S_MS_S;
+		rt5616->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 |= RT5616_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 |= RT5616_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5616_I2S_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT5616_I2S_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, RT5616_I2S1_SDP,
+		RT5616_I2S_MS_MASK | RT5616_I2S_BP_MASK |
+		RT5616_I2S_DF_MASK, reg_val);
+
+
+	return 0;
+}
+
+static int rt5616_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+	unsigned int reg_val = 0;
+
+	if (freq == rt5616->sysclk && clk_id == rt5616->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5616_SCLK_S_MCLK:
+		reg_val |= RT5616_SCLK_SRC_MCLK;
+		break;
+	case RT5616_SCLK_S_PLL1:
+		reg_val |= RT5616_SCLK_SRC_PLL1;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	snd_soc_update_bits(codec, RT5616_GLB_CLK,
+		RT5616_SCLK_SRC_MASK, reg_val);
+	rt5616->sysclk = freq;
+	rt5616->sysclk_src = clk_id;
+
+	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+	return 0;
+}
+
+static int rt5616_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 rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (source == rt5616->pll_src && freq_in == rt5616->pll_in &&
+	    freq_out == rt5616->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(codec->dev, "PLL disabled\n");
+
+		rt5616->pll_in = 0;
+		rt5616->pll_out = 0;
+		snd_soc_update_bits(codec, RT5616_GLB_CLK,
+			RT5616_SCLK_SRC_MASK, RT5616_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (source) {
+	case RT5616_PLL1_S_MCLK:
+		snd_soc_update_bits(codec, RT5616_GLB_CLK,
+			RT5616_PLL1_SRC_MASK, RT5616_PLL1_SRC_MCLK);
+		break;
+	case RT5616_PLL1_S_BCLK1:
+	case RT5616_PLL1_S_BCLK2:
+		snd_soc_update_bits(codec, RT5616_GLB_CLK,
+			RT5616_PLL1_SRC_MASK, RT5616_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, RT5616_PLL_CTRL1,
+		pll_code.n_code << RT5616_PLL_N_SFT | pll_code.k_code);
+	snd_soc_write(codec, RT5616_PLL_CTRL2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5616_PLL_M_SFT |
+		pll_code.m_bp << RT5616_PLL_M_BP_SFT);
+
+	rt5616->pll_in = freq_in;
+	rt5616->pll_out = freq_out;
+	rt5616->pll_src = source;
+
+	return 0;
+}
+
+static int rt5616_set_bias_level(struct snd_soc_codec *codec,
+			enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_STANDBY:
+		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+			snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+				RT5616_PWR_VREF1 | RT5616_PWR_MB |
+				RT5616_PWR_BG | RT5616_PWR_VREF2,
+				RT5616_PWR_VREF1 | RT5616_PWR_MB |
+				RT5616_PWR_BG | RT5616_PWR_VREF2);
+			mdelay(10);
+			snd_soc_update_bits(codec, RT5616_PWR_ANLG1,
+				RT5616_PWR_FV1 | RT5616_PWR_FV2,
+				RT5616_PWR_FV1 | RT5616_PWR_FV2);
+			snd_soc_update_bits(codec, RT5616_D_MISC,
+				RT5616_D_GATE_EN, RT5616_D_GATE_EN);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_update_bits(codec, RT5616_D_MISC, RT5616_D_GATE_EN, 0);
+		snd_soc_write(codec, RT5616_PWR_DIG1, 0x0000);
+		snd_soc_write(codec, RT5616_PWR_DIG2, 0x0000);
+		snd_soc_write(codec, RT5616_PWR_VOL, 0x0000);
+		snd_soc_write(codec, RT5616_PWR_MIXER, 0x0000);
+		snd_soc_write(codec, RT5616_PWR_ANLG1, 0x0000);
+		snd_soc_write(codec, RT5616_PWR_ANLG2, 0x0000);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5616_probe(struct snd_soc_codec *codec)
+{
+	struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+
+	rt5616->codec = codec;
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5616_suspend(struct snd_soc_codec *codec)
+{
+	struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+
+	regcache_cache_only(rt5616->regmap, true);
+	regcache_mark_dirty(rt5616->regmap);
+
+	return 0;
+}
+
+static int rt5616_resume(struct snd_soc_codec *codec)
+{
+	struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
+
+	regcache_cache_only(rt5616->regmap, false);
+	regcache_sync(rt5616->regmap);
+	return 0;
+}
+#else
+#define rt5616_suspend NULL
+#define rt5616_resume NULL
+#endif
+
+#define RT5616_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#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 = {
+	.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[] = {
+	{
+		.name = "rt5616-aif1",
+		.id = RT5616_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5616_STEREO_RATES,
+			.formats = RT5616_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5616_STEREO_RATES,
+			.formats = RT5616_FORMATS,
+		},
+		.ops = &rt5616_aif_dai_ops,
+	},
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5616 = {
+	.probe = rt5616_probe,
+	.suspend = rt5616_suspend,
+	.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),
+};
+
+static const struct regmap_config rt5616_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.use_single_rw = true,
+	.max_register = RT5616_DEVICE_ID + 1 + (ARRAY_SIZE(rt5616_ranges) *
+					       RT5616_PR_SPACING),
+	.volatile_reg = rt5616_volatile_register,
+	.readable_reg = rt5616_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5616_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5616_reg),
+	.ranges = rt5616_ranges,
+	.num_ranges = ARRAY_SIZE(rt5616_ranges),
+};
+
+static const struct i2c_device_id rt5616_i2c_id[] = {
+	{ "rt5616", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt5616_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rt5616_of_match[] = {
+	{ .compatible = "realtek,rt5616", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5616_of_match);
+#endif
+
+static int rt5616_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5616_priv *rt5616;
+	unsigned int val;
+	int ret;
+
+	rt5616 = devm_kzalloc(&i2c->dev, sizeof(struct rt5616_priv),
+				GFP_KERNEL);
+	if (rt5616 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, rt5616);
+
+	rt5616->regmap = devm_regmap_init_i2c(i2c, &rt5616_regmap);
+	if (IS_ERR(rt5616->regmap)) {
+		ret = PTR_ERR(rt5616->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt5616->regmap, RT5616_DEVICE_ID, &val);
+	if (val != 0x6281) {
+		dev_err(&i2c->dev,
+			"Device with ID register %#x is not rt5616\n",
+			val);
+		return -ENODEV;
+	}
+	regmap_write(rt5616->regmap, RT5616_RESET, 0);
+	regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1,
+		RT5616_PWR_VREF1 | RT5616_PWR_MB |
+		RT5616_PWR_BG | RT5616_PWR_VREF2,
+		RT5616_PWR_VREF1 | RT5616_PWR_MB |
+		RT5616_PWR_BG | RT5616_PWR_VREF2);
+	mdelay(10);
+	regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1,
+		RT5616_PWR_FV1 | RT5616_PWR_FV2,
+		RT5616_PWR_FV1 | RT5616_PWR_FV2);
+
+	ret = regmap_register_patch(rt5616->regmap, init_list,
+				    ARRAY_SIZE(init_list));
+	if (ret != 0)
+		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+	regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1,
+		RT5616_PWR_LDO_DVO_MASK, RT5616_PWR_LDO_DVO_1_2V);
+
+	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5616,
+			rt5616_dai, ARRAY_SIZE(rt5616_dai));
+
+}
+
+static int rt5616_i2c_remove(struct i2c_client *i2c)
+{
+	snd_soc_unregister_codec(&i2c->dev);
+
+	return 0;
+}
+
+static void rt5616_i2c_shutdown(struct i2c_client *client)
+{
+	struct rt5616_priv *rt5616 = i2c_get_clientdata(client);
+
+	regmap_write(rt5616->regmap, RT5616_HP_VOL, 0xc8c8);
+	regmap_write(rt5616->regmap, RT5616_LOUT_CTRL1, 0xc8c8);
+
+}
+
+static struct i2c_driver rt5616_i2c_driver = {
+	.driver = {
+		.name = "rt5616",
+		.of_match_table = of_match_ptr(rt5616_of_match),
+	},
+	.probe = rt5616_i2c_probe,
+	.remove = rt5616_i2c_remove,
+	.shutdown = rt5616_i2c_shutdown,
+	.id_table = rt5616_i2c_id,
+};
+module_i2c_driver(rt5616_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5616 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt5616.h b/sound/soc/codecs/rt5616.h
new file mode 100644
index 0000000..f88cddd
--- /dev/null
+++ b/sound/soc/codecs/rt5616.h
@@ -0,0 +1,1819 @@
+/*
+ * rt5616.h  --  RT5616 ALSA SoC audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ * Author: Johnny Hsu <johnnyhsu@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 __RT5616_H__
+#define __RT5616_H__
+
+/* Info */
+#define RT5616_RESET				0x00
+#define RT5616_VERSION_ID			0xfd
+#define RT5616_VENDOR_ID			0xfe
+#define RT5616_DEVICE_ID			0xff
+/*  I/O - Output */
+#define RT5616_HP_VOL				0x02
+#define RT5616_LOUT_CTRL1			0x03
+#define RT5616_LOUT_CTRL2			0x05
+/* I/O - Input */
+#define RT5616_IN1_IN2				0x0d
+#define RT5616_INL1_INR1_VOL			0x0f
+/* I/O - ADC/DAC/DMIC */
+#define RT5616_DAC1_DIG_VOL			0x19
+#define RT5616_ADC_DIG_VOL			0x1c
+#define RT5616_ADC_BST_VOL			0x1e
+/* Mixer - D-D */
+#define RT5616_STO1_ADC_MIXER			0x27
+#define RT5616_AD_DA_MIXER			0x29
+#define RT5616_STO_DAC_MIXER			0x2a
+
+/* Mixer - ADC */
+#define RT5616_REC_L1_MIXER			0x3b
+#define RT5616_REC_L2_MIXER			0x3c
+#define RT5616_REC_R1_MIXER			0x3d
+#define RT5616_REC_R2_MIXER			0x3e
+/* Mixer - DAC */
+#define RT5616_HPO_MIXER			0x45
+#define RT5616_OUT_L1_MIXER			0x4d
+#define RT5616_OUT_L2_MIXER			0x4e
+#define RT5616_OUT_L3_MIXER			0x4f
+#define RT5616_OUT_R1_MIXER			0x50
+#define RT5616_OUT_R2_MIXER			0x51
+#define RT5616_OUT_R3_MIXER			0x52
+#define RT5616_LOUT_MIXER			0x53
+/* Power */
+#define RT5616_PWR_DIG1				0x61
+#define RT5616_PWR_DIG2				0x62
+#define RT5616_PWR_ANLG1			0x63
+#define RT5616_PWR_ANLG2			0x64
+#define RT5616_PWR_MIXER			0x65
+#define RT5616_PWR_VOL				0x66
+/* Private Register Control */
+#define RT5616_PRIV_INDEX			0x6a
+#define RT5616_PRIV_DATA			0x6c
+/* Format - ADC/DAC */
+#define RT5616_I2S1_SDP				0x70
+#define RT5616_ADDA_CLK1			0x73
+#define RT5616_ADDA_CLK2			0x74
+
+/* Function - Analog */
+#define RT5616_GLB_CLK				0x80
+#define RT5616_PLL_CTRL1			0x81
+#define RT5616_PLL_CTRL2			0x82
+#define RT5616_HP_OVCD				0x8b
+#define RT5616_DEPOP_M1				0x8e
+#define RT5616_DEPOP_M2				0x8f
+#define RT5616_DEPOP_M3				0x90
+#define RT5616_CHARGE_PUMP			0x91
+#define RT5616_PV_DET_SPK_G			0x92
+#define RT5616_MICBIAS				0x93
+#define RT5616_A_JD_CTL1			0x94
+#define RT5616_A_JD_CTL2			0x95
+/* Function - Digital */
+#define RT5616_EQ_CTRL1				0xb0
+#define RT5616_EQ_CTRL2				0xb1
+#define RT5616_WIND_FILTER			0xb2
+#define RT5616_DRC_AGC_1			0xb4
+#define RT5616_DRC_AGC_2			0xb5
+#define RT5616_DRC_AGC_3			0xb6
+#define RT5616_SVOL_ZC				0xb7
+#define RT5616_JD_CTRL1				0xbb
+#define RT5616_JD_CTRL2				0xbc
+#define RT5616_IRQ_CTRL1			0xbd
+#define RT5616_IRQ_CTRL2			0xbe
+#define RT5616_INT_IRQ_ST			0xbf
+#define RT5616_GPIO_CTRL1			0xc0
+#define RT5616_GPIO_CTRL2			0xc1
+#define RT5616_GPIO_CTRL3			0xc2
+#define RT5616_PGM_REG_ARR1			0xc8
+#define RT5616_PGM_REG_ARR2			0xc9
+#define RT5616_PGM_REG_ARR3			0xca
+#define RT5616_PGM_REG_ARR4			0xcb
+#define RT5616_PGM_REG_ARR5			0xcc
+#define RT5616_SCB_FUNC				0xcd
+#define RT5616_SCB_CTRL				0xce
+#define RT5616_BASE_BACK			0xcf
+#define RT5616_MP3_PLUS1			0xd0
+#define RT5616_MP3_PLUS2			0xd1
+#define RT5616_ADJ_HPF_CTRL1			0xd3
+#define RT5616_ADJ_HPF_CTRL2			0xd4
+#define RT5616_HP_CALIB_AMP_DET			0xd6
+#define RT5616_HP_CALIB2			0xd7
+#define RT5616_SV_ZCD1				0xd9
+#define RT5616_SV_ZCD2				0xda
+#define RT5616_D_MISC				0xfa
+/* Dummy Register */
+#define RT5616_DUMMY2				0xfb
+#define RT5616_DUMMY3				0xfc
+
+
+/* Index of Codec Private Register definition */
+#define RT5616_BIAS_CUR1			0x12
+#define RT5616_BIAS_CUR3			0x14
+#define RT5616_CLSD_INT_REG1			0x1c
+#define RT5616_MAMP_INT_REG2			0x37
+#define RT5616_CHOP_DAC_ADC			0x3d
+#define RT5616_3D_SPK				0x63
+#define RT5616_WND_1				0x6c
+#define RT5616_WND_2				0x6d
+#define RT5616_WND_3				0x6e
+#define RT5616_WND_4				0x6f
+#define RT5616_WND_5				0x70
+#define RT5616_WND_8				0x73
+#define RT5616_DIP_SPK_INF			0x75
+#define RT5616_HP_DCC_INT1			0x77
+#define RT5616_EQ_BW_LOP			0xa0
+#define RT5616_EQ_GN_LOP			0xa1
+#define RT5616_EQ_FC_BP1			0xa2
+#define RT5616_EQ_BW_BP1			0xa3
+#define RT5616_EQ_GN_BP1			0xa4
+#define RT5616_EQ_FC_BP2			0xa5
+#define RT5616_EQ_BW_BP2			0xa6
+#define RT5616_EQ_GN_BP2			0xa7
+#define RT5616_EQ_FC_BP3			0xa8
+#define RT5616_EQ_BW_BP3			0xa9
+#define RT5616_EQ_GN_BP3			0xaa
+#define RT5616_EQ_FC_BP4			0xab
+#define RT5616_EQ_BW_BP4			0xac
+#define RT5616_EQ_GN_BP4			0xad
+#define RT5616_EQ_FC_HIP1			0xae
+#define RT5616_EQ_GN_HIP1			0xaf
+#define RT5616_EQ_FC_HIP2			0xb0
+#define RT5616_EQ_BW_HIP2			0xb1
+#define RT5616_EQ_GN_HIP2			0xb2
+#define RT5616_EQ_PRE_VOL			0xb3
+#define RT5616_EQ_PST_VOL			0xb4
+
+
+/* global definition */
+#define RT5616_L_MUTE				(0x1 << 15)
+#define RT5616_L_MUTE_SFT			15
+#define RT5616_VOL_L_MUTE			(0x1 << 14)
+#define RT5616_VOL_L_SFT			14
+#define RT5616_R_MUTE				(0x1 << 7)
+#define RT5616_R_MUTE_SFT			7
+#define RT5616_VOL_R_MUTE			(0x1 << 6)
+#define RT5616_VOL_R_SFT			6
+#define RT5616_L_VOL_MASK			(0x3f << 8)
+#define RT5616_L_VOL_SFT			8
+#define RT5616_R_VOL_MASK			(0x3f)
+#define RT5616_R_VOL_SFT			0
+
+/* LOUT Control 2(0x05) */
+#define RT5616_EN_DFO				(0x1 << 15)
+
+/* IN1 and IN2 Control (0x0d) */
+/* IN3 and IN4 Control (0x0e) */
+#define RT5616_BST_MASK1			(0xf<<12)
+#define RT5616_BST_SFT1				12
+#define RT5616_BST_MASK2			(0xf<<8)
+#define RT5616_BST_SFT2				8
+#define RT5616_IN_DF1				(0x1 << 7)
+#define RT5616_IN_SFT1				7
+#define RT5616_IN_DF2				(0x1 << 6)
+#define RT5616_IN_SFT2				6
+
+/* INL1 and INR1 Volume Control (0x0f) */
+#define RT5616_INL_VOL_MASK			(0x1f << 8)
+#define RT5616_INL_VOL_SFT			8
+#define RT5616_INR_SEL_MASK			(0x1 << 7)
+#define RT5616_INR_SEL_SFT			7
+#define RT5616_INR_SEL_IN4N			(0x0 << 7)
+#define RT5616_INR_SEL_MONON			(0x1 << 7)
+#define RT5616_INR_VOL_MASK			(0x1f)
+#define RT5616_INR_VOL_SFT			0
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5616_DAC_L1_VOL_MASK			(0xff << 8)
+#define RT5616_DAC_L1_VOL_SFT			8
+#define RT5616_DAC_R1_VOL_MASK			(0xff)
+#define RT5616_DAC_R1_VOL_SFT			0
+
+/* DAC2 Digital Volume (0x1a) */
+#define RT5616_DAC_L2_VOL_MASK			(0xff << 8)
+#define RT5616_DAC_L2_VOL_SFT			8
+#define RT5616_DAC_R2_VOL_MASK			(0xff)
+#define RT5616_DAC_R2_VOL_SFT			0
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5616_ADC_L_VOL_MASK			(0x7f << 8)
+#define RT5616_ADC_L_VOL_SFT			8
+#define RT5616_ADC_R_VOL_MASK			(0x7f)
+#define RT5616_ADC_R_VOL_SFT			0
+
+/* Mono ADC Digital Volume Control (0x1d) */
+#define RT5616_M_MONO_ADC_L			(0x1 << 15)
+#define RT5616_M_MONO_ADC_L_SFT			15
+#define RT5616_MONO_ADC_L_VOL_MASK		(0x7f << 8)
+#define RT5616_MONO_ADC_L_VOL_SFT		8
+#define RT5616_M_MONO_ADC_R			(0x1 << 7)
+#define RT5616_M_MONO_ADC_R_SFT			7
+#define RT5616_MONO_ADC_R_VOL_MASK		(0x7f)
+#define RT5616_MONO_ADC_R_VOL_SFT		0
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5616_ADC_L_BST_MASK			(0x3 << 14)
+#define RT5616_ADC_L_BST_SFT			14
+#define RT5616_ADC_R_BST_MASK			(0x3 << 12)
+#define RT5616_ADC_R_BST_SFT			12
+#define RT5616_ADC_COMP_MASK			(0x3 << 10)
+#define RT5616_ADC_COMP_SFT			10
+
+/* Stereo ADC1 Mixer Control (0x27) */
+#define RT5616_M_STO1_ADC_L1			(0x1 << 14)
+#define RT5616_M_STO1_ADC_L1_SFT		14
+#define RT5616_M_STO1_ADC_R1			(0x1 << 6)
+#define RT5616_M_STO1_ADC_R1_SFT		6
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5616_M_ADCMIX_L			(0x1 << 15)
+#define RT5616_M_ADCMIX_L_SFT			15
+#define RT5616_M_IF1_DAC_L			(0x1 << 14)
+#define RT5616_M_IF1_DAC_L_SFT			14
+#define RT5616_M_ADCMIX_R			(0x1 << 7)
+#define RT5616_M_ADCMIX_R_SFT			7
+#define RT5616_M_IF1_DAC_R			(0x1 << 6)
+#define RT5616_M_IF1_DAC_R_SFT			6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5616_M_DAC_L1_MIXL			(0x1 << 14)
+#define RT5616_M_DAC_L1_MIXL_SFT		14
+#define RT5616_DAC_L1_STO_L_VOL_MASK		(0x1 << 13)
+#define RT5616_DAC_L1_STO_L_VOL_SFT		13
+#define RT5616_M_DAC_R1_MIXL			(0x1 << 9)
+#define RT5616_M_DAC_R1_MIXL_SFT		9
+#define RT5616_DAC_R1_STO_L_VOL_MASK		(0x1 << 8)
+#define RT5616_DAC_R1_STO_L_VOL_SFT		8
+#define RT5616_M_DAC_R1_MIXR			(0x1 << 6)
+#define RT5616_M_DAC_R1_MIXR_SFT		6
+#define RT5616_DAC_R1_STO_R_VOL_MASK		(0x1 << 5)
+#define RT5616_DAC_R1_STO_R_VOL_SFT		5
+#define RT5616_M_DAC_L1_MIXR			(0x1 << 1)
+#define RT5616_M_DAC_L1_MIXR_SFT		1
+#define RT5616_DAC_L1_STO_R_VOL_MASK		(0x1)
+#define RT5616_DAC_L1_STO_R_VOL_SFT		0
+
+/* DD Mixer Control (0x2b) */
+#define RT5616_M_STO_DD_L1			(0x1 << 14)
+#define RT5616_M_STO_DD_L1_SFT			14
+#define RT5616_STO_DD_L1_VOL_MASK		(0x1 << 13)
+#define RT5616_DAC_DD_L1_VOL_SFT		13
+#define RT5616_M_STO_DD_L2			(0x1 << 12)
+#define RT5616_M_STO_DD_L2_SFT			12
+#define RT5616_STO_DD_L2_VOL_MASK		(0x1 << 11)
+#define RT5616_STO_DD_L2_VOL_SFT		11
+#define RT5616_M_STO_DD_R2_L			(0x1 << 10)
+#define RT5616_M_STO_DD_R2_L_SFT		10
+#define RT5616_STO_DD_R2_L_VOL_MASK		(0x1 << 9)
+#define RT5616_STO_DD_R2_L_VOL_SFT		9
+#define RT5616_M_STO_DD_R1			(0x1 << 6)
+#define RT5616_M_STO_DD_R1_SFT			6
+#define RT5616_STO_DD_R1_VOL_MASK		(0x1 << 5)
+#define RT5616_STO_DD_R1_VOL_SFT		5
+#define RT5616_M_STO_DD_R2			(0x1 << 4)
+#define RT5616_M_STO_DD_R2_SFT			4
+#define RT5616_STO_DD_R2_VOL_MASK		(0x1 << 3)
+#define RT5616_STO_DD_R2_VOL_SFT		3
+#define RT5616_M_STO_DD_L2_R			(0x1 << 2)
+#define RT5616_M_STO_DD_L2_R_SFT		2
+#define RT5616_STO_DD_L2_R_VOL_MASK		(0x1 << 1)
+#define RT5616_STO_DD_L2_R_VOL_SFT		1
+
+/* Digital Mixer Control (0x2c) */
+#define RT5616_M_STO_L_DAC_L			(0x1 << 15)
+#define RT5616_M_STO_L_DAC_L_SFT		15
+#define RT5616_STO_L_DAC_L_VOL_MASK		(0x1 << 14)
+#define RT5616_STO_L_DAC_L_VOL_SFT		14
+#define RT5616_M_DAC_L2_DAC_L			(0x1 << 13)
+#define RT5616_M_DAC_L2_DAC_L_SFT		13
+#define RT5616_DAC_L2_DAC_L_VOL_MASK		(0x1 << 12)
+#define RT5616_DAC_L2_DAC_L_VOL_SFT		12
+#define RT5616_M_STO_R_DAC_R			(0x1 << 11)
+#define RT5616_M_STO_R_DAC_R_SFT		11
+#define RT5616_STO_R_DAC_R_VOL_MASK		(0x1 << 10)
+#define RT5616_STO_R_DAC_R_VOL_SFT		10
+#define RT5616_M_DAC_R2_DAC_R			(0x1 << 9)
+#define RT5616_M_DAC_R2_DAC_R_SFT		9
+#define RT5616_DAC_R2_DAC_R_VOL_MASK		(0x1 << 8)
+#define RT5616_DAC_R2_DAC_R_VOL_SFT		8
+
+/* DSP Path Control 1 (0x2d) */
+#define RT5616_RXDP_SRC_MASK			(0x1 << 15)
+#define RT5616_RXDP_SRC_SFT			15
+#define RT5616_RXDP_SRC_NOR			(0x0 << 15)
+#define RT5616_RXDP_SRC_DIV3			(0x1 << 15)
+#define RT5616_TXDP_SRC_MASK			(0x1 << 14)
+#define RT5616_TXDP_SRC_SFT			14
+#define RT5616_TXDP_SRC_NOR			(0x0 << 14)
+#define RT5616_TXDP_SRC_DIV3			(0x1 << 14)
+
+/* DSP Path Control 2 (0x2e) */
+#define RT5616_DAC_L2_SEL_MASK			(0x3 << 14)
+#define RT5616_DAC_L2_SEL_SFT			14
+#define RT5616_DAC_L2_SEL_IF2			(0x0 << 14)
+#define RT5616_DAC_L2_SEL_IF3			(0x1 << 14)
+#define RT5616_DAC_L2_SEL_TXDC			(0x2 << 14)
+#define RT5616_DAC_L2_SEL_BASS			(0x3 << 14)
+#define RT5616_DAC_R2_SEL_MASK			(0x3 << 12)
+#define RT5616_DAC_R2_SEL_SFT			12
+#define RT5616_DAC_R2_SEL_IF2			(0x0 << 12)
+#define RT5616_DAC_R2_SEL_IF3			(0x1 << 12)
+#define RT5616_DAC_R2_SEL_TXDC			(0x2 << 12)
+#define RT5616_IF2_ADC_L_SEL_MASK		(0x1 << 11)
+#define RT5616_IF2_ADC_L_SEL_SFT		11
+#define RT5616_IF2_ADC_L_SEL_TXDP		(0x0 << 11)
+#define RT5616_IF2_ADC_L_SEL_PASS		(0x1 << 11)
+#define RT5616_IF2_ADC_R_SEL_MASK		(0x1 << 10)
+#define RT5616_IF2_ADC_R_SEL_SFT		10
+#define RT5616_IF2_ADC_R_SEL_TXDP		(0x0 << 10)
+#define RT5616_IF2_ADC_R_SEL_PASS		(0x1 << 10)
+#define RT5616_RXDC_SEL_MASK			(0x3 << 8)
+#define RT5616_RXDC_SEL_SFT			8
+#define RT5616_RXDC_SEL_NOR			(0x0 << 8)
+#define RT5616_RXDC_SEL_L2R			(0x1 << 8)
+#define RT5616_RXDC_SEL_R2L			(0x2 << 8)
+#define RT5616_RXDC_SEL_SWAP			(0x3 << 8)
+#define RT5616_RXDP_SEL_MASK			(0x3 << 6)
+#define RT5616_RXDP_SEL_SFT			6
+#define RT5616_RXDP_SEL_NOR			(0x0 << 6)
+#define RT5616_RXDP_SEL_L2R			(0x1 << 6)
+#define RT5616_RXDP_SEL_R2L			(0x2 << 6)
+#define RT5616_RXDP_SEL_SWAP			(0x3 << 6)
+#define RT5616_TXDC_SEL_MASK			(0x3 << 4)
+#define RT5616_TXDC_SEL_SFT			4
+#define RT5616_TXDC_SEL_NOR			(0x0 << 4)
+#define RT5616_TXDC_SEL_L2R			(0x1 << 4)
+#define RT5616_TXDC_SEL_R2L			(0x2 << 4)
+#define RT5616_TXDC_SEL_SWAP			(0x3 << 4)
+#define RT5616_TXDP_SEL_MASK			(0x3 << 2)
+#define RT5616_TXDP_SEL_SFT			2
+#define RT5616_TXDP_SEL_NOR			(0x0 << 2)
+#define RT5616_TXDP_SEL_L2R			(0x1 << 2)
+#define RT5616_TXDP_SEL_R2L			(0x2 << 2)
+#define RT5616_TRXDP_SEL_SWAP			(0x3 << 2)
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5616_G_LN_L2_RM_L_MASK		(0x7 << 13)
+#define RT5616_G_IN_L2_RM_L_SFT			13
+#define RT5616_G_LN_L1_RM_L_MASK		(0x7 << 10)
+#define RT5616_G_IN_L1_RM_L_SFT			10
+#define RT5616_G_BST3_RM_L_MASK			(0x7 << 4)
+#define RT5616_G_BST3_RM_L_SFT			4
+#define RT5616_G_BST2_RM_L_MASK			(0x7 << 1)
+#define RT5616_G_BST2_RM_L_SFT			1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5616_G_BST1_RM_L_MASK			(0x7 << 13)
+#define RT5616_G_BST1_RM_L_SFT			13
+#define RT5616_G_OM_L_RM_L_MASK			(0x7 << 10)
+#define RT5616_G_OM_L_RM_L_SFT			10
+#define RT5616_M_IN2_L_RM_L			(0x1 << 6)
+#define RT5616_M_IN2_L_RM_L_SFT			6
+#define RT5616_M_IN1_L_RM_L			(0x1 << 5)
+#define RT5616_M_IN1_L_RM_L_SFT			5
+#define RT5616_M_BST3_RM_L			(0x1 << 3)
+#define RT5616_M_BST3_RM_L_SFT			3
+#define RT5616_M_BST2_RM_L			(0x1 << 2)
+#define RT5616_M_BST2_RM_L_SFT			2
+#define RT5616_M_BST1_RM_L			(0x1 << 1)
+#define RT5616_M_BST1_RM_L_SFT			1
+#define RT5616_M_OM_L_RM_L			(0x1)
+#define RT5616_M_OM_L_RM_L_SFT			0
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5616_G_IN2_R_RM_R_MASK		(0x7 << 13)
+#define RT5616_G_IN2_R_RM_R_SFT			13
+#define RT5616_G_IN1_R_RM_R_MASK		(0x7 << 10)
+#define RT5616_G_IN1_R_RM_R_SFT			10
+#define RT5616_G_BST3_RM_R_MASK			(0x7 << 4)
+#define RT5616_G_BST3_RM_R_SFT			4
+#define RT5616_G_BST2_RM_R_MASK			(0x7 << 1)
+#define RT5616_G_BST2_RM_R_SFT			1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5616_G_BST1_RM_R_MASK			(0x7 << 13)
+#define RT5616_G_BST1_RM_R_SFT			13
+#define RT5616_G_OM_R_RM_R_MASK			(0x7 << 10)
+#define RT5616_G_OM_R_RM_R_SFT			10
+#define RT5616_M_IN2_R_RM_R			(0x1 << 6)
+#define RT5616_M_IN2_R_RM_R_SFT			6
+#define RT5616_M_IN1_R_RM_R			(0x1 << 5)
+#define RT5616_M_IN1_R_RM_R_SFT			5
+#define RT5616_M_BST3_RM_R			(0x1 << 3)
+#define RT5616_M_BST3_RM_R_SFT			3
+#define RT5616_M_BST2_RM_R			(0x1 << 2)
+#define RT5616_M_BST2_RM_R_SFT			2
+#define RT5616_M_BST1_RM_R			(0x1 << 1)
+#define RT5616_M_BST1_RM_R_SFT			1
+#define RT5616_M_OM_R_RM_R			(0x1)
+#define RT5616_M_OM_R_RM_R_SFT			0
+
+/* HPMIX Control (0x45) */
+#define RT5616_M_DAC1_HM			(0x1 << 14)
+#define RT5616_M_DAC1_HM_SFT			14
+#define RT5616_M_HPVOL_HM			(0x1 << 13)
+#define RT5616_M_HPVOL_HM_SFT			13
+#define RT5616_G_HPOMIX_MASK			(0x1 << 12)
+#define RT5616_G_HPOMIX_SFT			12
+
+/* SPK Left Mixer Control (0x46) */
+#define RT5616_G_RM_L_SM_L_MASK			(0x3 << 14)
+#define RT5616_G_RM_L_SM_L_SFT			14
+#define RT5616_G_IN_L_SM_L_MASK			(0x3 << 12)
+#define RT5616_G_IN_L_SM_L_SFT			12
+#define RT5616_G_DAC_L1_SM_L_MASK		(0x3 << 10)
+#define RT5616_G_DAC_L1_SM_L_SFT		10
+#define RT5616_G_DAC_L2_SM_L_MASK		(0x3 << 8)
+#define RT5616_G_DAC_L2_SM_L_SFT		8
+#define RT5616_G_OM_L_SM_L_MASK			(0x3 << 6)
+#define RT5616_G_OM_L_SM_L_SFT			6
+#define RT5616_M_RM_L_SM_L			(0x1 << 5)
+#define RT5616_M_RM_L_SM_L_SFT			5
+#define RT5616_M_IN_L_SM_L			(0x1 << 4)
+#define RT5616_M_IN_L_SM_L_SFT			4
+#define RT5616_M_DAC_L1_SM_L			(0x1 << 3)
+#define RT5616_M_DAC_L1_SM_L_SFT		3
+#define RT5616_M_DAC_L2_SM_L			(0x1 << 2)
+#define RT5616_M_DAC_L2_SM_L_SFT		2
+#define RT5616_M_OM_L_SM_L			(0x1 << 1)
+#define RT5616_M_OM_L_SM_L_SFT			1
+
+/* SPK Right Mixer Control (0x47) */
+#define RT5616_G_RM_R_SM_R_MASK			(0x3 << 14)
+#define RT5616_G_RM_R_SM_R_SFT			14
+#define RT5616_G_IN_R_SM_R_MASK			(0x3 << 12)
+#define RT5616_G_IN_R_SM_R_SFT			12
+#define RT5616_G_DAC_R1_SM_R_MASK		(0x3 << 10)
+#define RT5616_G_DAC_R1_SM_R_SFT		10
+#define RT5616_G_DAC_R2_SM_R_MASK		(0x3 << 8)
+#define RT5616_G_DAC_R2_SM_R_SFT		8
+#define RT5616_G_OM_R_SM_R_MASK			(0x3 << 6)
+#define RT5616_G_OM_R_SM_R_SFT			6
+#define RT5616_M_RM_R_SM_R			(0x1 << 5)
+#define RT5616_M_RM_R_SM_R_SFT			5
+#define RT5616_M_IN_R_SM_R			(0x1 << 4)
+#define RT5616_M_IN_R_SM_R_SFT			4
+#define RT5616_M_DAC_R1_SM_R			(0x1 << 3)
+#define RT5616_M_DAC_R1_SM_R_SFT		3
+#define RT5616_M_DAC_R2_SM_R			(0x1 << 2)
+#define RT5616_M_DAC_R2_SM_R_SFT		2
+#define RT5616_M_OM_R_SM_R			(0x1 << 1)
+#define RT5616_M_OM_R_SM_R_SFT			1
+
+/* SPOLMIX Control (0x48) */
+#define RT5616_M_DAC_R1_SPM_L			(0x1 << 15)
+#define RT5616_M_DAC_R1_SPM_L_SFT		15
+#define RT5616_M_DAC_L1_SPM_L			(0x1 << 14)
+#define RT5616_M_DAC_L1_SPM_L_SFT		14
+#define RT5616_M_SV_R_SPM_L			(0x1 << 13)
+#define RT5616_M_SV_R_SPM_L_SFT			13
+#define RT5616_M_SV_L_SPM_L			(0x1 << 12)
+#define RT5616_M_SV_L_SPM_L_SFT			12
+#define RT5616_M_BST1_SPM_L			(0x1 << 11)
+#define RT5616_M_BST1_SPM_L_SFT			11
+
+/* SPORMIX Control (0x49) */
+#define RT5616_M_DAC_R1_SPM_R			(0x1 << 13)
+#define RT5616_M_DAC_R1_SPM_R_SFT		13
+#define RT5616_M_SV_R_SPM_R			(0x1 << 12)
+#define RT5616_M_SV_R_SPM_R_SFT			12
+#define RT5616_M_BST1_SPM_R			(0x1 << 11)
+#define RT5616_M_BST1_SPM_R_SFT			11
+
+/* SPOLMIX / SPORMIX Ratio Control (0x4a) */
+#define RT5616_SPO_CLSD_RATIO_MASK		(0x7)
+#define RT5616_SPO_CLSD_RATIO_SFT		0
+
+/* Mono Output Mixer Control (0x4c) */
+#define RT5616_M_DAC_R2_MM			(0x1 << 15)
+#define RT5616_M_DAC_R2_MM_SFT			15
+#define RT5616_M_DAC_L2_MM			(0x1 << 14)
+#define RT5616_M_DAC_L2_MM_SFT			14
+#define RT5616_M_OV_R_MM			(0x1 << 13)
+#define RT5616_M_OV_R_MM_SFT			13
+#define RT5616_M_OV_L_MM			(0x1 << 12)
+#define RT5616_M_OV_L_MM_SFT			12
+#define RT5616_M_BST1_MM			(0x1 << 11)
+#define RT5616_M_BST1_MM_SFT			11
+#define RT5616_G_MONOMIX_MASK			(0x1 << 10)
+#define RT5616_G_MONOMIX_SFT			10
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5616_G_BST2_OM_L_MASK			(0x7 << 10)
+#define RT5616_G_BST2_OM_L_SFT			10
+#define RT5616_G_BST1_OM_L_MASK			(0x7 << 7)
+#define RT5616_G_BST1_OM_L_SFT			7
+#define RT5616_G_IN1_L_OM_L_MASK		(0x7 << 4)
+#define RT5616_G_IN1_L_OM_L_SFT			4
+#define RT5616_G_RM_L_OM_L_MASK			(0x7 << 1)
+#define RT5616_G_RM_L_OM_L_SFT			1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5616_G_DAC_L1_OM_L_MASK		(0x7 << 7)
+#define RT5616_G_DAC_L1_OM_L_SFT		7
+#define RT5616_G_IN2_L_OM_L_MASK		(0x7 << 4)
+#define RT5616_G_IN2_L_OM_L_SFT			4
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5616_M_IN2_L_OM_L			(0x1 << 9)
+#define RT5616_M_IN2_L_OM_L_SFT			9
+#define RT5616_M_BST2_OM_L			(0x1 << 6)
+#define RT5616_M_BST2_OM_L_SFT			6
+#define RT5616_M_BST1_OM_L			(0x1 << 5)
+#define RT5616_M_BST1_OM_L_SFT			5
+#define RT5616_M_IN1_L_OM_L			(0x1 << 4)
+#define RT5616_M_IN1_L_OM_L_SFT			4
+#define RT5616_M_RM_L_OM_L			(0x1 << 3)
+#define RT5616_M_RM_L_OM_L_SFT			3
+#define RT5616_M_DAC_L1_OM_L			(0x1)
+#define RT5616_M_DAC_L1_OM_L_SFT		0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5616_G_BST2_OM_R_MASK			(0x7 << 10)
+#define RT5616_G_BST2_OM_R_SFT			10
+#define RT5616_G_BST1_OM_R_MASK			(0x7 << 7)
+#define RT5616_G_BST1_OM_R_SFT			7
+#define RT5616_G_IN1_R_OM_R_MASK		(0x7 << 4)
+#define RT5616_G_IN1_R_OM_R_SFT			4
+#define RT5616_G_RM_R_OM_R_MASK			(0x7 << 1)
+#define RT5616_G_RM_R_OM_R_SFT			1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5616_G_DAC_R1_OM_R_MASK		(0x7 << 7)
+#define RT5616_G_DAC_R1_OM_R_SFT		7
+#define RT5616_G_IN2_R_OM_R_MASK		(0x7 << 4)
+#define RT5616_G_IN2_R_OM_R_SFT			4
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5616_M_IN2_R_OM_R			(0x1 << 9)
+#define RT5616_M_IN2_R_OM_R_SFT			9
+#define RT5616_M_BST2_OM_R			(0x1 << 6)
+#define RT5616_M_BST2_OM_R_SFT			6
+#define RT5616_M_BST1_OM_R			(0x1 << 5)
+#define RT5616_M_BST1_OM_R_SFT			5
+#define RT5616_M_IN1_R_OM_R			(0x1 << 4)
+#define RT5616_M_IN1_R_OM_R_SFT			4
+#define RT5616_M_RM_R_OM_R			(0x1 << 3)
+#define RT5616_M_RM_R_OM_R_SFT			3
+#define RT5616_M_DAC_R1_OM_R			(0x1)
+#define RT5616_M_DAC_R1_OM_R_SFT		0
+
+/* LOUT Mixer Control (0x53) */
+#define RT5616_M_DAC_L1_LM			(0x1 << 15)
+#define RT5616_M_DAC_L1_LM_SFT			15
+#define RT5616_M_DAC_R1_LM			(0x1 << 14)
+#define RT5616_M_DAC_R1_LM_SFT			14
+#define RT5616_M_OV_L_LM			(0x1 << 13)
+#define RT5616_M_OV_L_LM_SFT			13
+#define RT5616_M_OV_R_LM			(0x1 << 12)
+#define RT5616_M_OV_R_LM_SFT			12
+#define RT5616_G_LOUTMIX_MASK			(0x1 << 11)
+#define RT5616_G_LOUTMIX_SFT			11
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5616_PWR_I2S1				(0x1 << 15)
+#define RT5616_PWR_I2S1_BIT			15
+#define RT5616_PWR_I2S2				(0x1 << 14)
+#define RT5616_PWR_I2S2_BIT			14
+#define RT5616_PWR_DAC_L1			(0x1 << 12)
+#define RT5616_PWR_DAC_L1_BIT			12
+#define RT5616_PWR_DAC_R1			(0x1 << 11)
+#define RT5616_PWR_DAC_R1_BIT			11
+#define RT5616_PWR_ADC_L			(0x1 << 2)
+#define RT5616_PWR_ADC_L_BIT			2
+#define RT5616_PWR_ADC_R			(0x1 << 1)
+#define RT5616_PWR_ADC_R_BIT			1
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5616_PWR_ADC_STO1_F			(0x1 << 15)
+#define RT5616_PWR_ADC_STO1_F_BIT		15
+#define RT5616_PWR_DAC_STO1_F			(0x1 << 11)
+#define RT5616_PWR_DAC_STO1_F_BIT		11
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5616_PWR_VREF1			(0x1 << 15)
+#define RT5616_PWR_VREF1_BIT			15
+#define RT5616_PWR_FV1				(0x1 << 14)
+#define RT5616_PWR_FV1_BIT			14
+#define RT5616_PWR_MB				(0x1 << 13)
+#define RT5616_PWR_MB_BIT			13
+#define RT5616_PWR_LM				(0x1 << 12)
+#define RT5616_PWR_LM_BIT			12
+#define RT5616_PWR_BG				(0x1 << 11)
+#define RT5616_PWR_BG_BIT			11
+#define RT5616_PWR_HP_L				(0x1 << 7)
+#define RT5616_PWR_HP_L_BIT			7
+#define RT5616_PWR_HP_R				(0x1 << 6)
+#define RT5616_PWR_HP_R_BIT			6
+#define RT5616_PWR_HA				(0x1 << 5)
+#define RT5616_PWR_HA_BIT			5
+#define RT5616_PWR_VREF2			(0x1 << 4)
+#define RT5616_PWR_VREF2_BIT			4
+#define RT5616_PWR_FV2				(0x1 << 3)
+#define RT5616_PWR_FV2_BIT			3
+#define RT5616_PWR_LDO				(0x1 << 2)
+#define RT5616_PWR_LDO_BIT			2
+#define RT5616_PWR_LDO_DVO_MASK			(0x3)
+#define RT5616_PWR_LDO_DVO_1_0V			0
+#define RT5616_PWR_LDO_DVO_1_1V			1
+#define RT5616_PWR_LDO_DVO_1_2V			2
+#define RT5616_PWR_LDO_DVO_1_3V			3
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5616_PWR_BST1				(0x1 << 15)
+#define RT5616_PWR_BST1_BIT			15
+#define RT5616_PWR_BST2				(0x1 << 14)
+#define RT5616_PWR_BST2_BIT			14
+#define RT5616_PWR_MB1				(0x1 << 11)
+#define RT5616_PWR_MB1_BIT			11
+#define RT5616_PWR_PLL				(0x1 << 9)
+#define RT5616_PWR_PLL_BIT			9
+#define RT5616_PWR_BST1_OP2			(0x1 << 5)
+#define RT5616_PWR_BST1_OP2_BIT			5
+#define RT5616_PWR_BST2_OP2			(0x1 << 4)
+#define RT5616_PWR_BST2_OP2_BIT			4
+#define RT5616_PWR_BST3_OP2			(0x1 << 3)
+#define RT5616_PWR_BST3_OP2_BIT			3
+#define RT5616_PWR_JD_M				(0x1 << 2)
+#define RT5616_PWM_JD_M_BIT			2
+#define RT5616_PWR_JD2				(0x1 << 1)
+#define RT5616_PWM_JD2_BIT			1
+#define RT5616_PWR_JD3				(0x1)
+#define RT5616_PWM_JD3_BIT			0
+
+/* Power Management for Mixer (0x65) */
+#define RT5616_PWR_OM_L				(0x1 << 15)
+#define RT5616_PWR_OM_L_BIT			15
+#define RT5616_PWR_OM_R				(0x1 << 14)
+#define RT5616_PWR_OM_R_BIT			14
+#define RT5616_PWR_RM_L				(0x1 << 11)
+#define RT5616_PWR_RM_L_BIT			11
+#define RT5616_PWR_RM_R				(0x1 << 10)
+#define RT5616_PWR_RM_R_BIT			10
+
+/* Power Management for Volume (0x66) */
+#define RT5616_PWR_OV_L				(0x1 << 13)
+#define RT5616_PWR_OV_L_BIT			13
+#define RT5616_PWR_OV_R				(0x1 << 12)
+#define RT5616_PWR_OV_R_BIT			12
+#define RT5616_PWR_HV_L				(0x1 << 11)
+#define RT5616_PWR_HV_L_BIT			11
+#define RT5616_PWR_HV_R				(0x1 << 10)
+#define RT5616_PWR_HV_R_BIT			10
+#define RT5616_PWR_IN1_L			(0x1 << 9)
+#define RT5616_PWR_IN1_L_BIT			9
+#define RT5616_PWR_IN1_R			(0x1 << 8)
+#define RT5616_PWR_IN1_R_BIT			8
+#define RT5616_PWR_IN2_L			(0x1 << 7)
+#define RT5616_PWR_IN2_L_BIT			7
+#define RT5616_PWR_IN2_R			(0x1 << 6)
+#define RT5616_PWR_IN2_R_BIT			6
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71) */
+#define RT5616_I2S_MS_MASK			(0x1 << 15)
+#define RT5616_I2S_MS_SFT			15
+#define RT5616_I2S_MS_M				(0x0 << 15)
+#define RT5616_I2S_MS_S				(0x1 << 15)
+#define RT5616_I2S_O_CP_MASK			(0x3 << 10)
+#define RT5616_I2S_O_CP_SFT			10
+#define RT5616_I2S_O_CP_OFF			(0x0 << 10)
+#define RT5616_I2S_O_CP_U_LAW			(0x1 << 10)
+#define RT5616_I2S_O_CP_A_LAW			(0x2 << 10)
+#define RT5616_I2S_I_CP_MASK			(0x3 << 8)
+#define RT5616_I2S_I_CP_SFT			8
+#define RT5616_I2S_I_CP_OFF			(0x0 << 8)
+#define RT5616_I2S_I_CP_U_LAW			(0x1 << 8)
+#define RT5616_I2S_I_CP_A_LAW			(0x2 << 8)
+#define RT5616_I2S_BP_MASK			(0x1 << 7)
+#define RT5616_I2S_BP_SFT			7
+#define RT5616_I2S_BP_NOR			(0x0 << 7)
+#define RT5616_I2S_BP_INV			(0x1 << 7)
+#define RT5616_I2S_DL_MASK			(0x3 << 2)
+#define RT5616_I2S_DL_SFT			2
+#define RT5616_I2S_DL_16			(0x0 << 2)
+#define RT5616_I2S_DL_20			(0x1 << 2)
+#define RT5616_I2S_DL_24			(0x2 << 2)
+#define RT5616_I2S_DL_8				(0x3 << 2)
+#define RT5616_I2S_DF_MASK			(0x3)
+#define RT5616_I2S_DF_SFT			0
+#define RT5616_I2S_DF_I2S			(0x0)
+#define RT5616_I2S_DF_LEFT			(0x1)
+#define RT5616_I2S_DF_PCM_A			(0x2)
+#define RT5616_I2S_DF_PCM_B			(0x3)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5616_I2S_PD1_MASK			(0x7 << 12)
+#define RT5616_I2S_PD1_SFT			12
+#define RT5616_I2S_PD1_1			(0x0 << 12)
+#define RT5616_I2S_PD1_2			(0x1 << 12)
+#define RT5616_I2S_PD1_3			(0x2 << 12)
+#define RT5616_I2S_PD1_4			(0x3 << 12)
+#define RT5616_I2S_PD1_6			(0x4 << 12)
+#define RT5616_I2S_PD1_8			(0x5 << 12)
+#define RT5616_I2S_PD1_12			(0x6 << 12)
+#define RT5616_I2S_PD1_16			(0x7 << 12)
+#define RT5616_I2S_BCLK_MS2_MASK		(0x1 << 11)
+#define RT5616_DAC_OSR_MASK			(0x3 << 2)
+#define RT5616_DAC_OSR_SFT			2
+#define RT5616_DAC_OSR_128			(0x0 << 2)
+#define RT5616_DAC_OSR_64			(0x1 << 2)
+#define RT5616_DAC_OSR_32			(0x2 << 2)
+#define RT5616_DAC_OSR_128_3			(0x3 << 2)
+#define RT5616_ADC_OSR_MASK			(0x3)
+#define RT5616_ADC_OSR_SFT			0
+#define RT5616_ADC_OSR_128			(0x0)
+#define RT5616_ADC_OSR_64			(0x1)
+#define RT5616_ADC_OSR_32			(0x2)
+#define RT5616_ADC_OSR_128_3			(0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5616_DAHPF_EN				(0x1 << 11)
+#define RT5616_DAHPF_EN_SFT			11
+#define RT5616_ADHPF_EN				(0x1 << 10)
+#define RT5616_ADHPF_EN_SFT			10
+
+/* TDM Control 1 (0x77) */
+#define RT5616_TDM_INTEL_SEL_MASK		(0x1 << 15)
+#define RT5616_TDM_INTEL_SEL_SFT		15
+#define RT5616_TDM_INTEL_SEL_64			(0x0 << 15)
+#define RT5616_TDM_INTEL_SEL_50			(0x1 << 15)
+#define RT5616_TDM_MODE_SEL_MASK		(0x1 << 14)
+#define RT5616_TDM_MODE_SEL_SFT			14
+#define RT5616_TDM_MODE_SEL_NOR			(0x0 << 14)
+#define RT5616_TDM_MODE_SEL_TDM			(0x1 << 14)
+#define RT5616_TDM_CH_NUM_SEL_MASK		(0x3 << 12)
+#define RT5616_TDM_CH_NUM_SEL_SFT		12
+#define RT5616_TDM_CH_NUM_SEL_2			(0x0 << 12)
+#define RT5616_TDM_CH_NUM_SEL_4			(0x1 << 12)
+#define RT5616_TDM_CH_NUM_SEL_6			(0x2 << 12)
+#define RT5616_TDM_CH_NUM_SEL_8			(0x3 << 12)
+#define RT5616_TDM_CH_LEN_SEL_MASK		(0x3 << 10)
+#define RT5616_TDM_CH_LEN_SEL_SFT		10
+#define RT5616_TDM_CH_LEN_SEL_16		(0x0 << 10)
+#define RT5616_TDM_CH_LEN_SEL_20		(0x1 << 10)
+#define RT5616_TDM_CH_LEN_SEL_24		(0x2 << 10)
+#define RT5616_TDM_CH_LEN_SEL_32		(0x3 << 10)
+#define RT5616_TDM_ADC_SEL_MASK			(0x1 << 9)
+#define RT5616_TDM_ADC_SEL_SFT			9
+#define RT5616_TDM_ADC_SEL_NOR			(0x0 << 9)
+#define RT5616_TDM_ADC_SEL_SWAP			(0x1 << 9)
+#define RT5616_TDM_ADC_START_SEL_MASK		(0x1 << 8)
+#define RT5616_TDM_ADC_START_SEL_SFT		8
+#define RT5616_TDM_ADC_START_SEL_SL0		(0x0 << 8)
+#define RT5616_TDM_ADC_START_SEL_SL4		(0x1 << 8)
+#define RT5616_TDM_I2S_CH2_SEL_MASK		(0x3 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_SFT		6
+#define RT5616_TDM_I2S_CH2_SEL_LR		(0x0 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_RL		(0x1 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_LL		(0x2 << 6)
+#define RT5616_TDM_I2S_CH2_SEL_RR		(0x3 << 6)
+#define RT5616_TDM_I2S_CH4_SEL_MASK		(0x3 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_SFT		4
+#define RT5616_TDM_I2S_CH4_SEL_LR		(0x0 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_RL		(0x1 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_LL		(0x2 << 4)
+#define RT5616_TDM_I2S_CH4_SEL_RR		(0x3 << 4)
+#define RT5616_TDM_I2S_CH6_SEL_MASK		(0x3 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_SFT		2
+#define RT5616_TDM_I2S_CH6_SEL_LR		(0x0 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_RL		(0x1 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_LL		(0x2 << 2)
+#define RT5616_TDM_I2S_CH6_SEL_RR		(0x3 << 2)
+#define RT5616_TDM_I2S_CH8_SEL_MASK		(0x3)
+#define RT5616_TDM_I2S_CH8_SEL_SFT		0
+#define RT5616_TDM_I2S_CH8_SEL_LR		(0x0)
+#define RT5616_TDM_I2S_CH8_SEL_RL		(0x1)
+#define RT5616_TDM_I2S_CH8_SEL_LL		(0x2)
+#define RT5616_TDM_I2S_CH8_SEL_RR		(0x3)
+
+/* TDM Control 2 (0x78) */
+#define RT5616_TDM_LRCK_POL_SEL_MASK		(0x1 << 15)
+#define RT5616_TDM_LRCK_POL_SEL_SFT		15
+#define RT5616_TDM_LRCK_POL_SEL_NOR		(0x0 << 15)
+#define RT5616_TDM_LRCK_POL_SEL_INV		(0x1 << 15)
+#define RT5616_TDM_CH_VAL_SEL_MASK		(0x1 << 14)
+#define RT5616_TDM_CH_VAL_SEL_SFT		14
+#define RT5616_TDM_CH_VAL_SEL_CH01		(0x0 << 14)
+#define RT5616_TDM_CH_VAL_SEL_CH0123		(0x1 << 14)
+#define RT5616_TDM_CH_VAL_EN			(0x1 << 13)
+#define RT5616_TDM_CH_VAL_SFT			13
+#define RT5616_TDM_LPBK_EN			(0x1 << 12)
+#define RT5616_TDM_LPBK_SFT			12
+#define RT5616_TDM_LRCK_PULSE_SEL_MASK		(0x1 << 11)
+#define RT5616_TDM_LRCK_PULSE_SEL_SFT		11
+#define RT5616_TDM_LRCK_PULSE_SEL_BCLK		(0x0 << 11)
+#define RT5616_TDM_LRCK_PULSE_SEL_CH		(0x1 << 11)
+#define RT5616_TDM_END_EDGE_SEL_MASK		(0x1 << 10)
+#define RT5616_TDM_END_EDGE_SEL_SFT		10
+#define RT5616_TDM_END_EDGE_SEL_POS		(0x0 << 10)
+#define RT5616_TDM_END_EDGE_SEL_NEG		(0x1 << 10)
+#define RT5616_TDM_END_EDGE_EN			(0x1 << 9)
+#define RT5616_TDM_END_EDGE_EN_SFT		9
+#define RT5616_TDM_TRAN_EDGE_SEL_MASK		(0x1 << 8)
+#define RT5616_TDM_TRAN_EDGE_SEL_SFT		8
+#define RT5616_TDM_TRAN_EDGE_SEL_POS		(0x0 << 8)
+#define RT5616_TDM_TRAN_EDGE_SEL_NEG		(0x1 << 8)
+#define RT5616_M_TDM2_L				(0x1 << 7)
+#define RT5616_M_TDM2_L_SFT			7
+#define RT5616_M_TDM2_R				(0x1 << 6)
+#define RT5616_M_TDM2_R_SFT			6
+#define RT5616_M_TDM4_L				(0x1 << 5)
+#define RT5616_M_TDM4_L_SFT			5
+#define RT5616_M_TDM4_R				(0x1 << 4)
+#define RT5616_M_TDM4_R_SFT			4
+
+/* Global Clock Control (0x80) */
+#define RT5616_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5616_SCLK_SRC_SFT			14
+#define RT5616_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5616_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5616_PLL1_SRC_MASK			(0x3 << 12)
+#define RT5616_PLL1_SRC_SFT			12
+#define RT5616_PLL1_SRC_MCLK			(0x0 << 12)
+#define RT5616_PLL1_SRC_BCLK1			(0x1 << 12)
+#define RT5616_PLL1_SRC_BCLK2			(0x2 << 12)
+#define RT5616_PLL1_PD_MASK			(0x1 << 3)
+#define RT5616_PLL1_PD_SFT			3
+#define RT5616_PLL1_PD_1			(0x0 << 3)
+#define RT5616_PLL1_PD_2			(0x1 << 3)
+
+#define RT5616_PLL_INP_MAX			40000000
+#define RT5616_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5616_PLL_N_MAX			0x1ff
+#define RT5616_PLL_N_MASK			(RT5616_PLL_N_MAX << 7)
+#define RT5616_PLL_N_SFT			7
+#define RT5616_PLL_K_MAX			0x1f
+#define RT5616_PLL_K_MASK			(RT5616_PLL_K_MAX)
+#define RT5616_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5616_PLL_M_MAX			0xf
+#define RT5616_PLL_M_MASK			(RT5616_PLL_M_MAX << 12)
+#define RT5616_PLL_M_SFT			12
+#define RT5616_PLL_M_BP				(0x1 << 11)
+#define RT5616_PLL_M_BP_SFT			11
+
+/* PLL tracking mode 1 (0x83) */
+#define RT5616_STO1_T_MASK			(0x1 << 15)
+#define RT5616_STO1_T_SFT			15
+#define RT5616_STO1_T_SCLK			(0x0 << 15)
+#define RT5616_STO1_T_LRCK1			(0x1 << 15)
+#define RT5616_STO2_T_MASK			(0x1 << 12)
+#define RT5616_STO2_T_SFT			12
+#define RT5616_STO2_T_I2S2			(0x0 << 12)
+#define RT5616_STO2_T_LRCK2			(0x1 << 12)
+#define RT5616_ASRC2_REF_MASK			(0x1 << 11)
+#define RT5616_ASRC2_REF_SFT			11
+#define RT5616_ASRC2_REF_LRCK2			(0x0 << 11)
+#define RT5616_ASRC2_REF_LRCK1			(0x1 << 11)
+#define RT5616_DMIC_1_M_MASK			(0x1 << 9)
+#define RT5616_DMIC_1_M_SFT			9
+#define RT5616_DMIC_1_M_NOR			(0x0 << 9)
+#define RT5616_DMIC_1_M_ASYN			(0x1 << 9)
+
+/* PLL tracking mode 2 (0x84) */
+#define RT5616_STO1_ASRC_EN			(0x1 << 15)
+#define RT5616_STO1_ASRC_EN_SFT			15
+#define RT5616_STO2_ASRC_EN			(0x1 << 14)
+#define RT5616_STO2_ASRC_EN_SFT			14
+#define RT5616_STO1_DAC_M_MASK			(0x1 << 13)
+#define RT5616_STO1_DAC_M_SFT			13
+#define RT5616_STO1_DAC_M_NOR			(0x0 << 13)
+#define RT5616_STO1_DAC_M_ASRC			(0x1 << 13)
+#define RT5616_STO2_DAC_M_MASK			(0x1 << 12)
+#define RT5616_STO2_DAC_M_SFT			12
+#define RT5616_STO2_DAC_M_NOR			(0x0 << 12)
+#define RT5616_STO2_DAC_M_ASRC			(0x1 << 12)
+#define RT5616_ADC_M_MASK			(0x1 << 11)
+#define RT5616_ADC_M_SFT			11
+#define RT5616_ADC_M_NOR			(0x0 << 11)
+#define RT5616_ADC_M_ASRC			(0x1 << 11)
+#define RT5616_I2S1_R_D_MASK			(0x1 << 4)
+#define RT5616_I2S1_R_D_SFT			4
+#define RT5616_I2S1_R_D_DIS			(0x0 << 4)
+#define RT5616_I2S1_R_D_EN			(0x1 << 4)
+#define RT5616_I2S2_R_D_MASK			(0x1 << 3)
+#define RT5616_I2S2_R_D_SFT			3
+#define RT5616_I2S2_R_D_DIS			(0x0 << 3)
+#define RT5616_I2S2_R_D_EN			(0x1 << 3)
+#define RT5616_PRE_SCLK_MASK			(0x3)
+#define RT5616_PRE_SCLK_SFT			0
+#define RT5616_PRE_SCLK_512			(0x0)
+#define RT5616_PRE_SCLK_1024			(0x1)
+#define RT5616_PRE_SCLK_2048			(0x2)
+
+/* PLL tracking mode 3 (0x85) */
+#define RT5616_I2S1_RATE_MASK			(0xf << 12)
+#define RT5616_I2S1_RATE_SFT			12
+#define RT5616_I2S2_RATE_MASK			(0xf << 8)
+#define RT5616_I2S2_RATE_SFT			8
+#define RT5616_G_ASRC_LP_MASK			(0x1 << 3)
+#define RT5616_G_ASRC_LP_SFT			3
+#define RT5616_ASRC_LP_F_M			(0x1 << 2)
+#define RT5616_ASRC_LP_F_SFT			2
+#define RT5616_ASRC_LP_F_NOR			(0x0 << 2)
+#define RT5616_ASRC_LP_F_SB			(0x1 << 2)
+#define RT5616_FTK_PH_DET_MASK			(0x3)
+#define RT5616_FTK_PH_DET_SFT			0
+#define RT5616_FTK_PH_DET_DIV1			(0x0)
+#define RT5616_FTK_PH_DET_DIV2			(0x1)
+#define RT5616_FTK_PH_DET_DIV4			(0x2)
+#define RT5616_FTK_PH_DET_DIV8			(0x3)
+
+/*PLL tracking mode 6 (0x89) */
+#define RT5616_I2S1_PD_MASK			(0x7 << 12)
+#define RT5616_I2S1_PD_SFT			12
+#define RT5616_I2S2_PD_MASK			(0x7 << 8)
+#define RT5616_I2S2_PD_SFT			8
+
+/*PLL tracking mode 7 (0x8a) */
+#define RT5616_FSI1_RATE_MASK			(0xf << 12)
+#define RT5616_FSI1_RATE_SFT			12
+#define RT5616_FSI2_RATE_MASK			(0xf << 8)
+#define RT5616_FSI2_RATE_SFT			8
+
+/* HPOUT Over Current Detection (0x8b) */
+#define RT5616_HP_OVCD_MASK			(0x1 << 10)
+#define RT5616_HP_OVCD_SFT			10
+#define RT5616_HP_OVCD_DIS			(0x0 << 10)
+#define RT5616_HP_OVCD_EN			(0x1 << 10)
+#define RT5616_HP_OC_TH_MASK			(0x3 << 8)
+#define RT5616_HP_OC_TH_SFT			8
+#define RT5616_HP_OC_TH_90			(0x0 << 8)
+#define RT5616_HP_OC_TH_105			(0x1 << 8)
+#define RT5616_HP_OC_TH_120			(0x2 << 8)
+#define RT5616_HP_OC_TH_135			(0x3 << 8)
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5616_SMT_TRIG_MASK			(0x1 << 15)
+#define RT5616_SMT_TRIG_SFT			15
+#define RT5616_SMT_TRIG_DIS			(0x0 << 15)
+#define RT5616_SMT_TRIG_EN			(0x1 << 15)
+#define RT5616_HP_L_SMT_MASK			(0x1 << 9)
+#define RT5616_HP_L_SMT_SFT			9
+#define RT5616_HP_L_SMT_DIS			(0x0 << 9)
+#define RT5616_HP_L_SMT_EN			(0x1 << 9)
+#define RT5616_HP_R_SMT_MASK			(0x1 << 8)
+#define RT5616_HP_R_SMT_SFT			8
+#define RT5616_HP_R_SMT_DIS			(0x0 << 8)
+#define RT5616_HP_R_SMT_EN			(0x1 << 8)
+#define RT5616_HP_CD_PD_MASK			(0x1 << 7)
+#define RT5616_HP_CD_PD_SFT			7
+#define RT5616_HP_CD_PD_DIS			(0x0 << 7)
+#define RT5616_HP_CD_PD_EN			(0x1 << 7)
+#define RT5616_RSTN_MASK			(0x1 << 6)
+#define RT5616_RSTN_SFT				6
+#define RT5616_RSTN_DIS				(0x0 << 6)
+#define RT5616_RSTN_EN				(0x1 << 6)
+#define RT5616_RSTP_MASK			(0x1 << 5)
+#define RT5616_RSTP_SFT				5
+#define RT5616_RSTP_DIS				(0x0 << 5)
+#define RT5616_RSTP_EN				(0x1 << 5)
+#define RT5616_HP_CO_MASK			(0x1 << 4)
+#define RT5616_HP_CO_SFT			4
+#define RT5616_HP_CO_DIS			(0x0 << 4)
+#define RT5616_HP_CO_EN				(0x1 << 4)
+#define RT5616_HP_CP_MASK			(0x1 << 3)
+#define RT5616_HP_CP_SFT			3
+#define RT5616_HP_CP_PD				(0x0 << 3)
+#define RT5616_HP_CP_PU				(0x1 << 3)
+#define RT5616_HP_SG_MASK			(0x1 << 2)
+#define RT5616_HP_SG_SFT			2
+#define RT5616_HP_SG_DIS			(0x0 << 2)
+#define RT5616_HP_SG_EN				(0x1 << 2)
+#define RT5616_HP_DP_MASK			(0x1 << 1)
+#define RT5616_HP_DP_SFT			1
+#define RT5616_HP_DP_PD				(0x0 << 1)
+#define RT5616_HP_DP_PU				(0x1 << 1)
+#define RT5616_HP_CB_MASK			(0x1)
+#define RT5616_HP_CB_SFT			0
+#define RT5616_HP_CB_PD				(0x0)
+#define RT5616_HP_CB_PU				(0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5616_DEPOP_MASK			(0x1 << 13)
+#define RT5616_DEPOP_SFT			13
+#define RT5616_DEPOP_AUTO			(0x0 << 13)
+#define RT5616_DEPOP_MAN			(0x1 << 13)
+#define RT5616_RAMP_MASK			(0x1 << 12)
+#define RT5616_RAMP_SFT				12
+#define RT5616_RAMP_DIS				(0x0 << 12)
+#define RT5616_RAMP_EN				(0x1 << 12)
+#define RT5616_BPS_MASK				(0x1 << 11)
+#define RT5616_BPS_SFT				11
+#define RT5616_BPS_DIS				(0x0 << 11)
+#define RT5616_BPS_EN				(0x1 << 11)
+#define RT5616_FAST_UPDN_MASK			(0x1 << 10)
+#define RT5616_FAST_UPDN_SFT			10
+#define RT5616_FAST_UPDN_DIS			(0x0 << 10)
+#define RT5616_FAST_UPDN_EN			(0x1 << 10)
+#define RT5616_MRES_MASK			(0x3 << 8)
+#define RT5616_MRES_SFT				8
+#define RT5616_MRES_15MO			(0x0 << 8)
+#define RT5616_MRES_25MO			(0x1 << 8)
+#define RT5616_MRES_35MO			(0x2 << 8)
+#define RT5616_MRES_45MO			(0x3 << 8)
+#define RT5616_VLO_MASK				(0x1 << 7)
+#define RT5616_VLO_SFT				7
+#define RT5616_VLO_3V				(0x0 << 7)
+#define RT5616_VLO_32V				(0x1 << 7)
+#define RT5616_DIG_DP_MASK			(0x1 << 6)
+#define RT5616_DIG_DP_SFT			6
+#define RT5616_DIG_DP_DIS			(0x0 << 6)
+#define RT5616_DIG_DP_EN			(0x1 << 6)
+#define RT5616_DP_TH_MASK			(0x3 << 4)
+#define RT5616_DP_TH_SFT			4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5616_CP_SYS_MASK			(0x7 << 12)
+#define RT5616_CP_SYS_SFT			12
+#define RT5616_CP_FQ1_MASK			(0x7 << 8)
+#define RT5616_CP_FQ1_SFT			8
+#define RT5616_CP_FQ2_MASK			(0x7 << 4)
+#define RT5616_CP_FQ2_SFT			4
+#define RT5616_CP_FQ3_MASK			(0x7)
+#define RT5616_CP_FQ3_SFT			0
+#define RT5616_CP_FQ_1_5_KHZ			0
+#define RT5616_CP_FQ_3_KHZ			1
+#define RT5616_CP_FQ_6_KHZ			2
+#define RT5616_CP_FQ_12_KHZ			3
+#define RT5616_CP_FQ_24_KHZ			4
+#define RT5616_CP_FQ_48_KHZ			5
+#define RT5616_CP_FQ_96_KHZ			6
+#define RT5616_CP_FQ_192_KHZ			7
+
+/* HPOUT charge pump (0x91) */
+#define RT5616_OSW_L_MASK			(0x1 << 11)
+#define RT5616_OSW_L_SFT			11
+#define RT5616_OSW_L_DIS			(0x0 << 11)
+#define RT5616_OSW_L_EN				(0x1 << 11)
+#define RT5616_OSW_R_MASK			(0x1 << 10)
+#define RT5616_OSW_R_SFT			10
+#define RT5616_OSW_R_DIS			(0x0 << 10)
+#define RT5616_OSW_R_EN				(0x1 << 10)
+#define RT5616_PM_HP_MASK			(0x3 << 8)
+#define RT5616_PM_HP_SFT			8
+#define RT5616_PM_HP_LV				(0x0 << 8)
+#define RT5616_PM_HP_MV				(0x1 << 8)
+#define RT5616_PM_HP_HV				(0x2 << 8)
+#define RT5616_IB_HP_MASK			(0x3 << 6)
+#define RT5616_IB_HP_SFT			6
+#define RT5616_IB_HP_125IL			(0x0 << 6)
+#define RT5616_IB_HP_25IL			(0x1 << 6)
+#define RT5616_IB_HP_5IL			(0x2 << 6)
+#define RT5616_IB_HP_1IL			(0x3 << 6)
+
+/* Micbias Control (0x93) */
+#define RT5616_MIC1_BS_MASK			(0x1 << 15)
+#define RT5616_MIC1_BS_SFT			15
+#define RT5616_MIC1_BS_9AV			(0x0 << 15)
+#define RT5616_MIC1_BS_75AV			(0x1 << 15)
+#define RT5616_MIC1_CLK_MASK			(0x1 << 13)
+#define RT5616_MIC1_CLK_SFT			13
+#define RT5616_MIC1_CLK_DIS			(0x0 << 13)
+#define RT5616_MIC1_CLK_EN			(0x1 << 13)
+#define RT5616_MIC1_OVCD_MASK			(0x1 << 11)
+#define RT5616_MIC1_OVCD_SFT			11
+#define RT5616_MIC1_OVCD_DIS			(0x0 << 11)
+#define RT5616_MIC1_OVCD_EN			(0x1 << 11)
+#define RT5616_MIC1_OVTH_MASK			(0x3 << 9)
+#define RT5616_MIC1_OVTH_SFT			9
+#define RT5616_MIC1_OVTH_600UA			(0x0 << 9)
+#define RT5616_MIC1_OVTH_1500UA			(0x1 << 9)
+#define RT5616_MIC1_OVTH_2000UA			(0x2 << 9)
+#define RT5616_PWR_MB_MASK			(0x1 << 5)
+#define RT5616_PWR_MB_SFT			5
+#define RT5616_PWR_MB_PD			(0x0 << 5)
+#define RT5616_PWR_MB_PU			(0x1 << 5)
+#define RT5616_PWR_CLK12M_MASK			(0x1 << 4)
+#define RT5616_PWR_CLK12M_SFT			4
+#define RT5616_PWR_CLK12M_PD			(0x0 << 4)
+#define RT5616_PWR_CLK12M_PU			(0x1 << 4)
+
+/* Analog JD Control 1 (0x94) */
+#define RT5616_JD2_CMP_MASK			(0x7 << 12)
+#define RT5616_JD2_CMP_SFT			12
+#define RT5616_JD_PU				(0x1 << 11)
+#define RT5616_JD_PU_SFT			11
+#define RT5616_JD_PD				(0x1 << 10)
+#define RT5616_JD_PD_SFT			10
+#define RT5616_JD_MODE_SEL_MASK			(0x3 << 8)
+#define RT5616_JD_MODE_SEL_SFT			8
+#define RT5616_JD_MODE_SEL_M0			(0x0 << 8)
+#define RT5616_JD_MODE_SEL_M1			(0x1 << 8)
+#define RT5616_JD_MODE_SEL_M2			(0x2 << 8)
+#define RT5616_JD_M_CMP				(0x7 << 4)
+#define RT5616_JD_M_CMP_SFT			4
+#define RT5616_JD_M_PU				(0x1 << 3)
+#define RT5616_JD_M_PU_SFT			3
+#define RT5616_JD_M_PD				(0x1 << 2)
+#define RT5616_JD_M_PD_SFT			2
+#define RT5616_JD_M_MODE_SEL_MASK		(0x3)
+#define RT5616_JD_M_MODE_SEL_SFT		0
+#define RT5616_JD_M_MODE_SEL_M0			(0x0)
+#define RT5616_JD_M_MODE_SEL_M1			(0x1)
+#define RT5616_JD_M_MODE_SEL_M2			(0x2)
+
+/* Analog JD Control 2 (0x95) */
+#define RT5616_JD3_CMP_MASK			(0x7 << 12)
+#define RT5616_JD3_CMP_SFT			12
+
+/* EQ Control 1 (0xb0) */
+#define RT5616_EQ_SRC_MASK			(0x1 << 15)
+#define RT5616_EQ_SRC_SFT			15
+#define RT5616_EQ_SRC_DAC			(0x0 << 15)
+#define RT5616_EQ_SRC_ADC			(0x1 << 15)
+#define RT5616_EQ_UPD				(0x1 << 14)
+#define RT5616_EQ_UPD_BIT			14
+#define RT5616_EQ_CD_MASK			(0x1 << 13)
+#define RT5616_EQ_CD_SFT			13
+#define RT5616_EQ_CD_DIS			(0x0 << 13)
+#define RT5616_EQ_CD_EN				(0x1 << 13)
+#define RT5616_EQ_DITH_MASK			(0x3 << 8)
+#define RT5616_EQ_DITH_SFT			8
+#define RT5616_EQ_DITH_NOR			(0x0 << 8)
+#define RT5616_EQ_DITH_LSB			(0x1 << 8)
+#define RT5616_EQ_DITH_LSB_1			(0x2 << 8)
+#define RT5616_EQ_DITH_LSB_2			(0x3 << 8)
+#define RT5616_EQ_CD_F				(0x1 << 7)
+#define RT5616_EQ_CD_F_BIT			7
+#define RT5616_EQ_STA_HP2			(0x1 << 6)
+#define RT5616_EQ_STA_HP2_BIT			6
+#define RT5616_EQ_STA_HP1			(0x1 << 5)
+#define RT5616_EQ_STA_HP1_BIT			5
+#define RT5616_EQ_STA_BP4			(0x1 << 4)
+#define RT5616_EQ_STA_BP4_BIT			4
+#define RT5616_EQ_STA_BP3			(0x1 << 3)
+#define RT5616_EQ_STA_BP3_BIT			3
+#define RT5616_EQ_STA_BP2			(0x1 << 2)
+#define RT5616_EQ_STA_BP2_BIT			2
+#define RT5616_EQ_STA_BP1			(0x1 << 1)
+#define RT5616_EQ_STA_BP1_BIT			1
+#define RT5616_EQ_STA_LP			(0x1)
+#define RT5616_EQ_STA_LP_BIT			0
+
+/* EQ Control 2 (0xb1) */
+#define RT5616_EQ_HPF1_M_MASK			(0x1 << 8)
+#define RT5616_EQ_HPF1_M_SFT			8
+#define RT5616_EQ_HPF1_M_HI			(0x0 << 8)
+#define RT5616_EQ_HPF1_M_1ST			(0x1 << 8)
+#define RT5616_EQ_LPF1_M_MASK			(0x1 << 7)
+#define RT5616_EQ_LPF1_M_SFT			7
+#define RT5616_EQ_LPF1_M_LO			(0x0 << 7)
+#define RT5616_EQ_LPF1_M_1ST			(0x1 << 7)
+#define RT5616_EQ_HPF2_MASK			(0x1 << 6)
+#define RT5616_EQ_HPF2_SFT			6
+#define RT5616_EQ_HPF2_DIS			(0x0 << 6)
+#define RT5616_EQ_HPF2_EN			(0x1 << 6)
+#define RT5616_EQ_HPF1_MASK			(0x1 << 5)
+#define RT5616_EQ_HPF1_SFT			5
+#define RT5616_EQ_HPF1_DIS			(0x0 << 5)
+#define RT5616_EQ_HPF1_EN			(0x1 << 5)
+#define RT5616_EQ_BPF4_MASK			(0x1 << 4)
+#define RT5616_EQ_BPF4_SFT			4
+#define RT5616_EQ_BPF4_DIS			(0x0 << 4)
+#define RT5616_EQ_BPF4_EN			(0x1 << 4)
+#define RT5616_EQ_BPF3_MASK			(0x1 << 3)
+#define RT5616_EQ_BPF3_SFT			3
+#define RT5616_EQ_BPF3_DIS			(0x0 << 3)
+#define RT5616_EQ_BPF3_EN			(0x1 << 3)
+#define RT5616_EQ_BPF2_MASK			(0x1 << 2)
+#define RT5616_EQ_BPF2_SFT			2
+#define RT5616_EQ_BPF2_DIS			(0x0 << 2)
+#define RT5616_EQ_BPF2_EN			(0x1 << 2)
+#define RT5616_EQ_BPF1_MASK			(0x1 << 1)
+#define RT5616_EQ_BPF1_SFT			1
+#define RT5616_EQ_BPF1_DIS			(0x0 << 1)
+#define RT5616_EQ_BPF1_EN			(0x1 << 1)
+#define RT5616_EQ_LPF_MASK			(0x1)
+#define RT5616_EQ_LPF_SFT			0
+#define RT5616_EQ_LPF_DIS			(0x0)
+#define RT5616_EQ_LPF_EN			(0x1)
+#define RT5616_EQ_CTRL_MASK			(0x7f)
+
+/* Memory Test (0xb2) */
+#define RT5616_MT_MASK				(0x1 << 15)
+#define RT5616_MT_SFT				15
+#define RT5616_MT_DIS				(0x0 << 15)
+#define RT5616_MT_EN				(0x1 << 15)
+
+/* DRC/AGC Control 1 (0xb4) */
+#define RT5616_DRC_AGC_P_MASK			(0x1 << 15)
+#define RT5616_DRC_AGC_P_SFT			15
+#define RT5616_DRC_AGC_P_DAC			(0x0 << 15)
+#define RT5616_DRC_AGC_P_ADC			(0x1 << 15)
+#define RT5616_DRC_AGC_MASK			(0x1 << 14)
+#define RT5616_DRC_AGC_SFT			14
+#define RT5616_DRC_AGC_DIS			(0x0 << 14)
+#define RT5616_DRC_AGC_EN			(0x1 << 14)
+#define RT5616_DRC_AGC_UPD			(0x1 << 13)
+#define RT5616_DRC_AGC_UPD_BIT			13
+#define RT5616_DRC_AGC_AR_MASK			(0x1f << 8)
+#define RT5616_DRC_AGC_AR_SFT			8
+#define RT5616_DRC_AGC_R_MASK			(0x7 << 5)
+#define RT5616_DRC_AGC_R_SFT			5
+#define RT5616_DRC_AGC_R_48K			(0x1 << 5)
+#define RT5616_DRC_AGC_R_96K			(0x2 << 5)
+#define RT5616_DRC_AGC_R_192K			(0x3 << 5)
+#define RT5616_DRC_AGC_R_441K			(0x5 << 5)
+#define RT5616_DRC_AGC_R_882K			(0x6 << 5)
+#define RT5616_DRC_AGC_R_1764K			(0x7 << 5)
+#define RT5616_DRC_AGC_RC_MASK			(0x1f)
+#define RT5616_DRC_AGC_RC_SFT			0
+
+/* DRC/AGC Control 2 (0xb5) */
+#define RT5616_DRC_AGC_POB_MASK			(0x3f << 8)
+#define RT5616_DRC_AGC_POB_SFT			8
+#define RT5616_DRC_AGC_CP_MASK			(0x1 << 7)
+#define RT5616_DRC_AGC_CP_SFT			7
+#define RT5616_DRC_AGC_CP_DIS			(0x0 << 7)
+#define RT5616_DRC_AGC_CP_EN			(0x1 << 7)
+#define RT5616_DRC_AGC_CPR_MASK			(0x3 << 5)
+#define RT5616_DRC_AGC_CPR_SFT			5
+#define RT5616_DRC_AGC_CPR_1_1			(0x0 << 5)
+#define RT5616_DRC_AGC_CPR_1_2			(0x1 << 5)
+#define RT5616_DRC_AGC_CPR_1_3			(0x2 << 5)
+#define RT5616_DRC_AGC_CPR_1_4			(0x3 << 5)
+#define RT5616_DRC_AGC_PRB_MASK			(0x1f)
+#define RT5616_DRC_AGC_PRB_SFT			0
+
+/* DRC/AGC Control 3 (0xb6) */
+#define RT5616_DRC_AGC_NGB_MASK			(0xf << 12)
+#define RT5616_DRC_AGC_NGB_SFT			12
+#define RT5616_DRC_AGC_TAR_MASK			(0x1f << 7)
+#define RT5616_DRC_AGC_TAR_SFT			7
+#define RT5616_DRC_AGC_NG_MASK			(0x1 << 6)
+#define RT5616_DRC_AGC_NG_SFT			6
+#define RT5616_DRC_AGC_NG_DIS			(0x0 << 6)
+#define RT5616_DRC_AGC_NG_EN			(0x1 << 6)
+#define RT5616_DRC_AGC_NGH_MASK			(0x1 << 5)
+#define RT5616_DRC_AGC_NGH_SFT			5
+#define RT5616_DRC_AGC_NGH_DIS			(0x0 << 5)
+#define RT5616_DRC_AGC_NGH_EN			(0x1 << 5)
+#define RT5616_DRC_AGC_NGT_MASK			(0x1f)
+#define RT5616_DRC_AGC_NGT_SFT			0
+
+/* Jack Detect Control 1 (0xbb) */
+#define RT5616_JD_MASK				(0x7 << 13)
+#define RT5616_JD_SFT				13
+#define RT5616_JD_DIS				(0x0 << 13)
+#define RT5616_JD_GPIO1				(0x1 << 13)
+#define RT5616_JD_GPIO2				(0x2 << 13)
+#define RT5616_JD_GPIO3				(0x3 << 13)
+#define RT5616_JD_GPIO4				(0x4 << 13)
+#define RT5616_JD_GPIO5				(0x5 << 13)
+#define RT5616_JD_GPIO6				(0x6 << 13)
+#define RT5616_JD_HP_MASK			(0x1 << 11)
+#define RT5616_JD_HP_SFT			11
+#define RT5616_JD_HP_DIS			(0x0 << 11)
+#define RT5616_JD_HP_EN				(0x1 << 11)
+#define RT5616_JD_HP_TRG_MASK			(0x1 << 10)
+#define RT5616_JD_HP_TRG_SFT			10
+#define RT5616_JD_HP_TRG_LO			(0x0 << 10)
+#define RT5616_JD_HP_TRG_HI			(0x1 << 10)
+#define RT5616_JD_SPL_MASK			(0x1 << 9)
+#define RT5616_JD_SPL_SFT			9
+#define RT5616_JD_SPL_DIS			(0x0 << 9)
+#define RT5616_JD_SPL_EN			(0x1 << 9)
+#define RT5616_JD_SPL_TRG_MASK			(0x1 << 8)
+#define RT5616_JD_SPL_TRG_SFT			8
+#define RT5616_JD_SPL_TRG_LO			(0x0 << 8)
+#define RT5616_JD_SPL_TRG_HI			(0x1 << 8)
+#define RT5616_JD_SPR_MASK			(0x1 << 7)
+#define RT5616_JD_SPR_SFT			7
+#define RT5616_JD_SPR_DIS			(0x0 << 7)
+#define RT5616_JD_SPR_EN			(0x1 << 7)
+#define RT5616_JD_SPR_TRG_MASK			(0x1 << 6)
+#define RT5616_JD_SPR_TRG_SFT			6
+#define RT5616_JD_SPR_TRG_LO			(0x0 << 6)
+#define RT5616_JD_SPR_TRG_HI			(0x1 << 6)
+#define RT5616_JD_LO_MASK			(0x1 << 3)
+#define RT5616_JD_LO_SFT			3
+#define RT5616_JD_LO_DIS			(0x0 << 3)
+#define RT5616_JD_LO_EN				(0x1 << 3)
+#define RT5616_JD_LO_TRG_MASK			(0x1 << 2)
+#define RT5616_JD_LO_TRG_SFT			2
+#define RT5616_JD_LO_TRG_LO			(0x0 << 2)
+#define RT5616_JD_LO_TRG_HI			(0x1 << 2)
+
+/* Jack Detect Control 2 (0xbc) */
+#define RT5616_JD_TRG_SEL_MASK			(0x7 << 9)
+#define RT5616_JD_TRG_SEL_SFT			9
+#define RT5616_JD_TRG_SEL_GPIO			(0x0 << 9)
+#define RT5616_JD_TRG_SEL_JD1_1			(0x1 << 9)
+#define RT5616_JD_TRG_SEL_JD1_2			(0x2 << 9)
+#define RT5616_JD_TRG_SEL_JD2			(0x3 << 9)
+#define RT5616_JD_TRG_SEL_JD3			(0x4 << 9)
+#define RT5616_JD3_IRQ_EN			(0x1 << 8)
+#define RT5616_JD3_IRQ_EN_SFT			8
+#define RT5616_JD3_EN_STKY			(0x1 << 7)
+#define RT5616_JD3_EN_STKY_SFT			7
+#define RT5616_JD3_INV				(0x1 << 6)
+#define RT5616_JD3_INV_SFT			6
+
+/* IRQ Control 1 (0xbd) */
+#define RT5616_IRQ_JD_MASK			(0x1 << 15)
+#define RT5616_IRQ_JD_SFT			15
+#define RT5616_IRQ_JD_BP			(0x0 << 15)
+#define RT5616_IRQ_JD_NOR			(0x1 << 15)
+#define RT5616_JD_STKY_MASK			(0x1 << 13)
+#define RT5616_JD_STKY_SFT			13
+#define RT5616_JD_STKY_DIS			(0x0 << 13)
+#define RT5616_JD_STKY_EN			(0x1 << 13)
+#define RT5616_JD_P_MASK			(0x1 << 11)
+#define RT5616_JD_P_SFT				11
+#define RT5616_JD_P_NOR				(0x0 << 11)
+#define RT5616_JD_P_INV				(0x1 << 11)
+#define RT5616_JD1_1_IRQ_EN			(0x1 << 9)
+#define RT5616_JD1_1_IRQ_EN_SFT			9
+#define RT5616_JD1_1_EN_STKY			(0x1 << 8)
+#define RT5616_JD1_1_EN_STKY_SFT			8
+#define RT5616_JD1_1_INV			(0x1 << 7)
+#define RT5616_JD1_1_INV_SFT			7
+#define RT5616_JD1_2_IRQ_EN			(0x1 << 6)
+#define RT5616_JD1_2_IRQ_EN_SFT			6
+#define RT5616_JD1_2_EN_STKY			(0x1 << 5)
+#define RT5616_JD1_2_EN_STKY_SFT			5
+#define RT5616_JD1_2_INV			(0x1 << 4)
+#define RT5616_JD1_2_INV_SFT			4
+#define RT5616_JD2_IRQ_EN			(0x1 << 3)
+#define RT5616_JD2_IRQ_EN_SFT			3
+#define RT5616_JD2_EN_STKY			(0x1 << 2)
+#define RT5616_JD2_EN_STKY_SFT			2
+#define RT5616_JD2_INV				(0x1 << 1)
+#define RT5616_JD2_INV_SFT			1
+
+/* IRQ Control 2 (0xbe) */
+#define RT5616_IRQ_MB1_OC_MASK			(0x1 << 15)
+#define RT5616_IRQ_MB1_OC_SFT			15
+#define RT5616_IRQ_MB1_OC_BP			(0x0 << 15)
+#define RT5616_IRQ_MB1_OC_NOR			(0x1 << 15)
+#define RT5616_MB1_OC_STKY_MASK			(0x1 << 11)
+#define RT5616_MB1_OC_STKY_SFT			11
+#define RT5616_MB1_OC_STKY_DIS			(0x0 << 11)
+#define RT5616_MB1_OC_STKY_EN			(0x1 << 11)
+#define RT5616_MB1_OC_P_MASK			(0x1 << 7)
+#define RT5616_MB1_OC_P_SFT			7
+#define RT5616_MB1_OC_P_NOR			(0x0 << 7)
+#define RT5616_MB1_OC_P_INV			(0x1 << 7)
+#define RT5616_MB2_OC_P_MASK			(0x1 << 6)
+#define RT5616_MB1_OC_CLR			(0x1 << 3)
+#define RT5616_MB1_OC_CLR_SFT			3
+#define RT5616_STA_GPIO8			(0x1)
+#define RT5616_STA_GPIO8_BIT			0
+
+/* Internal Status and GPIO status (0xbf) */
+#define RT5616_STA_JD3				(0x1 << 15)
+#define RT5616_STA_JD3_BIT			15
+#define RT5616_STA_JD2				(0x1 << 14)
+#define RT5616_STA_JD2_BIT			14
+#define RT5616_STA_JD1_2			(0x1 << 13)
+#define RT5616_STA_JD1_2_BIT			13
+#define RT5616_STA_JD1_1			(0x1 << 12)
+#define RT5616_STA_JD1_1_BIT			12
+#define RT5616_STA_GP7				(0x1 << 11)
+#define RT5616_STA_GP7_BIT			11
+#define RT5616_STA_GP6				(0x1 << 10)
+#define RT5616_STA_GP6_BIT			10
+#define RT5616_STA_GP5				(0x1 << 9)
+#define RT5616_STA_GP5_BIT			9
+#define RT5616_STA_GP1				(0x1 << 8)
+#define RT5616_STA_GP1_BIT			8
+#define RT5616_STA_GP2				(0x1 << 7)
+#define RT5616_STA_GP2_BIT			7
+#define RT5616_STA_GP3				(0x1 << 6)
+#define RT5616_STA_GP3_BIT			6
+#define RT5616_STA_GP4				(0x1 << 5)
+#define RT5616_STA_GP4_BIT			5
+#define RT5616_STA_GP_JD			(0x1 << 4)
+#define RT5616_STA_GP_JD_BIT			4
+
+/* GPIO Control 1 (0xc0) */
+#define RT5616_GP1_PIN_MASK			(0x1 << 15)
+#define RT5616_GP1_PIN_SFT			15
+#define RT5616_GP1_PIN_GPIO1			(0x0 << 15)
+#define RT5616_GP1_PIN_IRQ			(0x1 << 15)
+#define RT5616_GP2_PIN_MASK			(0x1 << 14)
+#define RT5616_GP2_PIN_SFT			14
+#define RT5616_GP2_PIN_GPIO2			(0x0 << 14)
+#define RT5616_GP2_PIN_DMIC1_SCL		(0x1 << 14)
+#define RT5616_GPIO_M_MASK			(0x1 << 9)
+#define RT5616_GPIO_M_SFT			9
+#define RT5616_GPIO_M_FLT			(0x0 << 9)
+#define RT5616_GPIO_M_PH			(0x1 << 9)
+#define RT5616_I2S2_SEL_MASK			(0x1 << 8)
+#define RT5616_I2S2_SEL_SFT			8
+#define RT5616_I2S2_SEL_I2S			(0x0 << 8)
+#define RT5616_I2S2_SEL_GPIO			(0x1 << 8)
+#define RT5616_GP5_PIN_MASK			(0x1 << 7)
+#define RT5616_GP5_PIN_SFT			7
+#define RT5616_GP5_PIN_GPIO5			(0x0 << 7)
+#define RT5616_GP5_PIN_IRQ			(0x1 << 7)
+#define RT5616_GP6_PIN_MASK			(0x1 << 6)
+#define RT5616_GP6_PIN_SFT			6
+#define RT5616_GP6_PIN_GPIO6			(0x0 << 6)
+#define RT5616_GP6_PIN_DMIC_SDA			(0x1 << 6)
+#define RT5616_GP7_PIN_MASK			(0x1 << 5)
+#define RT5616_GP7_PIN_SFT			5
+#define RT5616_GP7_PIN_GPIO7			(0x0 << 5)
+#define RT5616_GP7_PIN_IRQ			(0x1 << 5)
+#define RT5616_GP8_PIN_MASK			(0x1 << 4)
+#define RT5616_GP8_PIN_SFT			4
+#define RT5616_GP8_PIN_GPIO8			(0x0 << 4)
+#define RT5616_GP8_PIN_DMIC_SDA			(0x1 << 4)
+#define RT5616_GPIO_PDM_SEL_MASK		(0x1 << 3)
+#define RT5616_GPIO_PDM_SEL_SFT			3
+#define RT5616_GPIO_PDM_SEL_GPIO		(0x0 << 3)
+#define RT5616_GPIO_PDM_SEL_PDM			(0x1 << 3)
+
+/* GPIO Control 2 (0xc1) */
+#define RT5616_GP5_DR_MASK			(0x1 << 14)
+#define RT5616_GP5_DR_SFT			14
+#define RT5616_GP5_DR_IN			(0x0 << 14)
+#define RT5616_GP5_DR_OUT			(0x1 << 14)
+#define RT5616_GP5_OUT_MASK			(0x1 << 13)
+#define RT5616_GP5_OUT_SFT			13
+#define RT5616_GP5_OUT_LO			(0x0 << 13)
+#define RT5616_GP5_OUT_HI			(0x1 << 13)
+#define RT5616_GP5_P_MASK			(0x1 << 12)
+#define RT5616_GP5_P_SFT			12
+#define RT5616_GP5_P_NOR			(0x0 << 12)
+#define RT5616_GP5_P_INV			(0x1 << 12)
+#define RT5616_GP4_DR_MASK			(0x1 << 11)
+#define RT5616_GP4_DR_SFT			11
+#define RT5616_GP4_DR_IN			(0x0 << 11)
+#define RT5616_GP4_DR_OUT			(0x1 << 11)
+#define RT5616_GP4_OUT_MASK			(0x1 << 10)
+#define RT5616_GP4_OUT_SFT			10
+#define RT5616_GP4_OUT_LO			(0x0 << 10)
+#define RT5616_GP4_OUT_HI			(0x1 << 10)
+#define RT5616_GP4_P_MASK			(0x1 << 9)
+#define RT5616_GP4_P_SFT			9
+#define RT5616_GP4_P_NOR			(0x0 << 9)
+#define RT5616_GP4_P_INV			(0x1 << 9)
+#define RT5616_GP3_DR_MASK			(0x1 << 8)
+#define RT5616_GP3_DR_SFT			8
+#define RT5616_GP3_DR_IN			(0x0 << 8)
+#define RT5616_GP3_DR_OUT			(0x1 << 8)
+#define RT5616_GP3_OUT_MASK			(0x1 << 7)
+#define RT5616_GP3_OUT_SFT			7
+#define RT5616_GP3_OUT_LO			(0x0 << 7)
+#define RT5616_GP3_OUT_HI			(0x1 << 7)
+#define RT5616_GP3_P_MASK			(0x1 << 6)
+#define RT5616_GP3_P_SFT			6
+#define RT5616_GP3_P_NOR			(0x0 << 6)
+#define RT5616_GP3_P_INV			(0x1 << 6)
+#define RT5616_GP2_DR_MASK			(0x1 << 5)
+#define RT5616_GP2_DR_SFT			5
+#define RT5616_GP2_DR_IN			(0x0 << 5)
+#define RT5616_GP2_DR_OUT			(0x1 << 5)
+#define RT5616_GP2_OUT_MASK			(0x1 << 4)
+#define RT5616_GP2_OUT_SFT			4
+#define RT5616_GP2_OUT_LO			(0x0 << 4)
+#define RT5616_GP2_OUT_HI			(0x1 << 4)
+#define RT5616_GP2_P_MASK			(0x1 << 3)
+#define RT5616_GP2_P_SFT			3
+#define RT5616_GP2_P_NOR			(0x0 << 3)
+#define RT5616_GP2_P_INV			(0x1 << 3)
+#define RT5616_GP1_DR_MASK			(0x1 << 2)
+#define RT5616_GP1_DR_SFT			2
+#define RT5616_GP1_DR_IN			(0x0 << 2)
+#define RT5616_GP1_DR_OUT			(0x1 << 2)
+#define RT5616_GP1_OUT_MASK			(0x1 << 1)
+#define RT5616_GP1_OUT_SFT			1
+#define RT5616_GP1_OUT_LO			(0x0 << 1)
+#define RT5616_GP1_OUT_HI			(0x1 << 1)
+#define RT5616_GP1_P_MASK			(0x1)
+#define RT5616_GP1_P_SFT			0
+#define RT5616_GP1_P_NOR			(0x0)
+#define RT5616_GP1_P_INV			(0x1)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5616_GP8_DR_MASK			(0x1 << 8)
+#define RT5616_GP8_DR_SFT			8
+#define RT5616_GP8_DR_IN			(0x0 << 8)
+#define RT5616_GP8_DR_OUT			(0x1 << 8)
+#define RT5616_GP8_OUT_MASK			(0x1 << 7)
+#define RT5616_GP8_OUT_SFT			7
+#define RT5616_GP8_OUT_LO			(0x0 << 7)
+#define RT5616_GP8_OUT_HI			(0x1 << 7)
+#define RT5616_GP8_P_MASK			(0x1 << 6)
+#define RT5616_GP8_P_SFT			6
+#define RT5616_GP8_P_NOR			(0x0 << 6)
+#define RT5616_GP8_P_INV			(0x1 << 6)
+#define RT5616_GP7_DR_MASK			(0x1 << 5)
+#define RT5616_GP7_DR_SFT			5
+#define RT5616_GP7_DR_IN			(0x0 << 5)
+#define RT5616_GP7_DR_OUT			(0x1 << 5)
+#define RT5616_GP7_OUT_MASK			(0x1 << 4)
+#define RT5616_GP7_OUT_SFT			4
+#define RT5616_GP7_OUT_LO			(0x0 << 4)
+#define RT5616_GP7_OUT_HI			(0x1 << 4)
+#define RT5616_GP7_P_MASK			(0x1 << 3)
+#define RT5616_GP7_P_SFT			3
+#define RT5616_GP7_P_NOR			(0x0 << 3)
+#define RT5616_GP7_P_INV			(0x1 << 3)
+#define RT5616_GP6_DR_MASK			(0x1 << 2)
+#define RT5616_GP6_DR_SFT			2
+#define RT5616_GP6_DR_IN			(0x0 << 2)
+#define RT5616_GP6_DR_OUT			(0x1 << 2)
+#define RT5616_GP6_OUT_MASK			(0x1 << 1)
+#define RT5616_GP6_OUT_SFT			1
+#define RT5616_GP6_OUT_LO			(0x0 << 1)
+#define RT5616_GP6_OUT_HI			(0x1 << 1)
+#define RT5616_GP6_P_MASK			(0x1)
+#define RT5616_GP6_P_SFT			0
+#define RT5616_GP6_P_NOR			(0x0)
+#define RT5616_GP6_P_INV			(0x1)
+
+/* Scramble Control (0xce) */
+#define RT5616_SCB_SWAP_MASK			(0x1 << 15)
+#define RT5616_SCB_SWAP_SFT			15
+#define RT5616_SCB_SWAP_DIS			(0x0 << 15)
+#define RT5616_SCB_SWAP_EN			(0x1 << 15)
+#define RT5616_SCB_MASK				(0x1 << 14)
+#define RT5616_SCB_SFT				14
+#define RT5616_SCB_DIS				(0x0 << 14)
+#define RT5616_SCB_EN				(0x1 << 14)
+
+/* Baseback Control (0xcf) */
+#define RT5616_BB_MASK				(0x1 << 15)
+#define RT5616_BB_SFT				15
+#define RT5616_BB_DIS				(0x0 << 15)
+#define RT5616_BB_EN				(0x1 << 15)
+#define RT5616_BB_CT_MASK			(0x7 << 12)
+#define RT5616_BB_CT_SFT			12
+#define RT5616_BB_CT_A				(0x0 << 12)
+#define RT5616_BB_CT_B				(0x1 << 12)
+#define RT5616_BB_CT_C				(0x2 << 12)
+#define RT5616_BB_CT_D				(0x3 << 12)
+#define RT5616_M_BB_L_MASK			(0x1 << 9)
+#define RT5616_M_BB_L_SFT			9
+#define RT5616_M_BB_R_MASK			(0x1 << 8)
+#define RT5616_M_BB_R_SFT			8
+#define RT5616_M_BB_HPF_L_MASK			(0x1 << 7)
+#define RT5616_M_BB_HPF_L_SFT			7
+#define RT5616_M_BB_HPF_R_MASK			(0x1 << 6)
+#define RT5616_M_BB_HPF_R_SFT			6
+#define RT5616_G_BB_BST_MASK			(0x3f)
+#define RT5616_G_BB_BST_SFT			0
+
+/* MP3 Plus Control 1 (0xd0) */
+#define RT5616_M_MP3_L_MASK			(0x1 << 15)
+#define RT5616_M_MP3_L_SFT			15
+#define RT5616_M_MP3_R_MASK			(0x1 << 14)
+#define RT5616_M_MP3_R_SFT			14
+#define RT5616_M_MP3_MASK			(0x1 << 13)
+#define RT5616_M_MP3_SFT			13
+#define RT5616_M_MP3_DIS			(0x0 << 13)
+#define RT5616_M_MP3_EN				(0x1 << 13)
+#define RT5616_EG_MP3_MASK			(0x1f << 8)
+#define RT5616_EG_MP3_SFT			8
+#define RT5616_MP3_HLP_MASK			(0x1 << 7)
+#define RT5616_MP3_HLP_SFT			7
+#define RT5616_MP3_HLP_DIS			(0x0 << 7)
+#define RT5616_MP3_HLP_EN			(0x1 << 7)
+#define RT5616_M_MP3_ORG_L_MASK			(0x1 << 6)
+#define RT5616_M_MP3_ORG_L_SFT			6
+#define RT5616_M_MP3_ORG_R_MASK			(0x1 << 5)
+#define RT5616_M_MP3_ORG_R_SFT			5
+
+/* MP3 Plus Control 2 (0xd1) */
+#define RT5616_MP3_WT_MASK			(0x1 << 13)
+#define RT5616_MP3_WT_SFT			13
+#define RT5616_MP3_WT_1_4			(0x0 << 13)
+#define RT5616_MP3_WT_1_2			(0x1 << 13)
+#define RT5616_OG_MP3_MASK			(0x1f << 8)
+#define RT5616_OG_MP3_SFT			8
+#define RT5616_HG_MP3_MASK			(0x3f)
+#define RT5616_HG_MP3_SFT			0
+
+/* 3D HP Control 1 (0xd2) */
+#define RT5616_3D_CF_MASK			(0x1 << 15)
+#define RT5616_3D_CF_SFT			15
+#define RT5616_3D_CF_DIS			(0x0 << 15)
+#define RT5616_3D_CF_EN				(0x1 << 15)
+#define RT5616_3D_HP_MASK			(0x1 << 14)
+#define RT5616_3D_HP_SFT			14
+#define RT5616_3D_HP_DIS			(0x0 << 14)
+#define RT5616_3D_HP_EN				(0x1 << 14)
+#define RT5616_3D_BT_MASK			(0x1 << 13)
+#define RT5616_3D_BT_SFT			13
+#define RT5616_3D_BT_DIS			(0x0 << 13)
+#define RT5616_3D_BT_EN				(0x1 << 13)
+#define RT5616_3D_1F_MIX_MASK			(0x3 << 11)
+#define RT5616_3D_1F_MIX_SFT			11
+#define RT5616_3D_HP_M_MASK			(0x1 << 10)
+#define RT5616_3D_HP_M_SFT			10
+#define RT5616_3D_HP_M_SUR			(0x0 << 10)
+#define RT5616_3D_HP_M_FRO			(0x1 << 10)
+#define RT5616_M_3D_HRTF_MASK			(0x1 << 9)
+#define RT5616_M_3D_HRTF_SFT			9
+#define RT5616_M_3D_D2H_MASK			(0x1 << 8)
+#define RT5616_M_3D_D2H_SFT			8
+#define RT5616_M_3D_D2R_MASK			(0x1 << 7)
+#define RT5616_M_3D_D2R_SFT			7
+#define RT5616_M_3D_REVB_MASK			(0x1 << 6)
+#define RT5616_M_3D_REVB_SFT			6
+
+/* Adjustable high pass filter control 1 (0xd3) */
+#define RT5616_2ND_HPF_MASK			(0x1 << 15)
+#define RT5616_2ND_HPF_SFT			15
+#define RT5616_2ND_HPF_DIS			(0x0 << 15)
+#define RT5616_2ND_HPF_EN			(0x1 << 15)
+#define RT5616_HPF_CF_L_MASK			(0x7 << 12)
+#define RT5616_HPF_CF_L_SFT			12
+#define RT5616_HPF_CF_R_MASK			(0x7 << 8)
+#define RT5616_HPF_CF_R_SFT			8
+#define RT5616_ZD_T_MASK			(0x3 << 6)
+#define RT5616_ZD_T_SFT				6
+#define RT5616_ZD_F_MASK			(0x3 << 4)
+#define RT5616_ZD_F_SFT				4
+#define RT5616_ZD_F_IM				(0x0 << 4)
+#define RT5616_ZD_F_ZC_IM			(0x1 << 4)
+#define RT5616_ZD_F_ZC_IOD			(0x2 << 4)
+#define RT5616_ZD_F_UN				(0x3 << 4)
+
+/* Adjustable high pass filter control 2 (0xd4) */
+#define RT5616_HPF_CF_L_NUM_MASK		(0x3f << 8)
+#define RT5616_HPF_CF_L_NUM_SFT			8
+#define RT5616_HPF_CF_R_NUM_MASK		(0x3f)
+#define RT5616_HPF_CF_R_NUM_SFT			0
+
+/* HP calibration control and Amp detection (0xd6) */
+#define RT5616_SI_DAC_MASK			(0x1 << 11)
+#define RT5616_SI_DAC_SFT			11
+#define RT5616_SI_DAC_AUTO			(0x0 << 11)
+#define RT5616_SI_DAC_TEST			(0x1 << 11)
+#define RT5616_DC_CAL_M_MASK			(0x1 << 10)
+#define RT5616_DC_CAL_M_SFT			10
+#define RT5616_DC_CAL_M_NOR			(0x0 << 10)
+#define RT5616_DC_CAL_M_CAL			(0x1 << 10)
+#define RT5616_DC_CAL_MASK			(0x1 << 9)
+#define RT5616_DC_CAL_SFT			9
+#define RT5616_DC_CAL_DIS			(0x0 << 9)
+#define RT5616_DC_CAL_EN			(0x1 << 9)
+#define RT5616_HPD_RCV_MASK			(0x7 << 6)
+#define RT5616_HPD_RCV_SFT			6
+#define RT5616_HPD_PS_MASK			(0x1 << 5)
+#define RT5616_HPD_PS_SFT			5
+#define RT5616_HPD_PS_DIS			(0x0 << 5)
+#define RT5616_HPD_PS_EN			(0x1 << 5)
+#define RT5616_CAL_M_MASK			(0x1 << 4)
+#define RT5616_CAL_M_SFT			4
+#define RT5616_CAL_M_DEP			(0x0 << 4)
+#define RT5616_CAL_M_CAL			(0x1 << 4)
+#define RT5616_CAL_MASK				(0x1 << 3)
+#define RT5616_CAL_SFT				3
+#define RT5616_CAL_DIS				(0x0 << 3)
+#define RT5616_CAL_EN				(0x1 << 3)
+#define RT5616_CAL_TEST_MASK			(0x1 << 2)
+#define RT5616_CAL_TEST_SFT			2
+#define RT5616_CAL_TEST_DIS			(0x0 << 2)
+#define RT5616_CAL_TEST_EN			(0x1 << 2)
+#define RT5616_CAL_P_MASK			(0x3)
+#define RT5616_CAL_P_SFT			0
+#define RT5616_CAL_P_NONE			(0x0)
+#define RT5616_CAL_P_CAL			(0x1)
+#define RT5616_CAL_P_DAC_CAL			(0x2)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5616_SV_MASK				(0x1 << 15)
+#define RT5616_SV_SFT				15
+#define RT5616_SV_DIS				(0x0 << 15)
+#define RT5616_SV_EN				(0x1 << 15)
+#define RT5616_OUT_SV_MASK			(0x1 << 13)
+#define RT5616_OUT_SV_SFT			13
+#define RT5616_OUT_SV_DIS			(0x0 << 13)
+#define RT5616_OUT_SV_EN			(0x1 << 13)
+#define RT5616_HP_SV_MASK			(0x1 << 12)
+#define RT5616_HP_SV_SFT			12
+#define RT5616_HP_SV_DIS			(0x0 << 12)
+#define RT5616_HP_SV_EN				(0x1 << 12)
+#define RT5616_ZCD_DIG_MASK			(0x1 << 11)
+#define RT5616_ZCD_DIG_SFT			11
+#define RT5616_ZCD_DIG_DIS			(0x0 << 11)
+#define RT5616_ZCD_DIG_EN			(0x1 << 11)
+#define RT5616_ZCD_MASK				(0x1 << 10)
+#define RT5616_ZCD_SFT				10
+#define RT5616_ZCD_PD				(0x0 << 10)
+#define RT5616_ZCD_PU				(0x1 << 10)
+#define RT5616_M_ZCD_MASK			(0x3f << 4)
+#define RT5616_M_ZCD_SFT			4
+#define RT5616_M_ZCD_OM_L			(0x1 << 7)
+#define RT5616_M_ZCD_OM_R			(0x1 << 6)
+#define RT5616_M_ZCD_RM_L			(0x1 << 5)
+#define RT5616_M_ZCD_RM_R			(0x1 << 4)
+#define RT5616_SV_DLY_MASK			(0xf)
+#define RT5616_SV_DLY_SFT			0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5616_ZCD_HP_MASK			(0x1 << 15)
+#define RT5616_ZCD_HP_SFT			15
+#define RT5616_ZCD_HP_DIS			(0x0 << 15)
+#define RT5616_ZCD_HP_EN			(0x1 << 15)
+
+/* Digital Misc Control (0xfa) */
+#define RT5616_I2S2_MS_SP_MASK			(0x1 << 8)
+#define RT5616_I2S2_MS_SP_SEL			8
+#define RT5616_I2S2_MS_SP_64			(0x0 << 8)
+#define RT5616_I2S2_MS_SP_50			(0x1 << 8)
+#define RT5616_CLK_DET_EN			(0x1 << 3)
+#define RT5616_CLK_DET_EN_SFT			3
+#define RT5616_AMP_DET_EN			(0x1 << 1)
+#define RT5616_AMP_DET_EN_SFT			1
+#define RT5616_D_GATE_EN			(0x1)
+#define RT5616_D_GATE_EN_SFT			0
+
+/* Codec Private Register definition */
+/* 3D Speaker Control (0x63) */
+#define RT5616_3D_SPK_MASK			(0x1 << 15)
+#define RT5616_3D_SPK_SFT			15
+#define RT5616_3D_SPK_DIS			(0x0 << 15)
+#define RT5616_3D_SPK_EN			(0x1 << 15)
+#define RT5616_3D_SPK_M_MASK			(0x3 << 13)
+#define RT5616_3D_SPK_M_SFT			13
+#define RT5616_3D_SPK_CG_MASK			(0x1f << 8)
+#define RT5616_3D_SPK_CG_SFT			8
+#define RT5616_3D_SPK_SG_MASK			(0x1f)
+#define RT5616_3D_SPK_SG_SFT			0
+
+/* Wind Noise Detection Control 1 (0x6c) */
+#define RT5616_WND_MASK				(0x1 << 15)
+#define RT5616_WND_SFT				15
+#define RT5616_WND_DIS				(0x0 << 15)
+#define RT5616_WND_EN				(0x1 << 15)
+
+/* Wind Noise Detection Control 2 (0x6d) */
+#define RT5616_WND_FC_NW_MASK			(0x3f << 10)
+#define RT5616_WND_FC_NW_SFT			10
+#define RT5616_WND_FC_WK_MASK			(0x3f << 4)
+#define RT5616_WND_FC_WK_SFT			4
+
+/* Wind Noise Detection Control 3 (0x6e) */
+#define RT5616_HPF_FC_MASK			(0x3f << 6)
+#define RT5616_HPF_FC_SFT			6
+#define RT5616_WND_FC_ST_MASK			(0x3f)
+#define RT5616_WND_FC_ST_SFT			0
+
+/* Wind Noise Detection Control 4 (0x6f) */
+#define RT5616_WND_TH_LO_MASK			(0x3ff)
+#define RT5616_WND_TH_LO_SFT			0
+
+/* Wind Noise Detection Control 5 (0x70) */
+#define RT5616_WND_TH_HI_MASK			(0x3ff)
+#define RT5616_WND_TH_HI_SFT			0
+
+/* Wind Noise Detection Control 8 (0x73) */
+#define RT5616_WND_WIND_MASK			(0x1 << 13) /* Read-Only */
+#define RT5616_WND_WIND_SFT			13
+#define RT5616_WND_STRONG_MASK			(0x1 << 12) /* Read-Only */
+#define RT5616_WND_STRONG_SFT			12
+enum {
+	RT5616_NO_WIND,
+	RT5616_BREEZE,
+	RT5616_STORM,
+};
+
+/* Dipole Speaker Interface (0x75) */
+#define RT5616_DP_ATT_MASK			(0x3 << 14)
+#define RT5616_DP_ATT_SFT			14
+#define RT5616_DP_SPK_MASK			(0x1 << 10)
+#define RT5616_DP_SPK_SFT			10
+#define RT5616_DP_SPK_DIS			(0x0 << 10)
+#define RT5616_DP_SPK_EN			(0x1 << 10)
+
+/* EQ Pre Volume Control (0xb3) */
+#define RT5616_EQ_PRE_VOL_MASK			(0xffff)
+#define RT5616_EQ_PRE_VOL_SFT			0
+
+/* EQ Post Volume Control (0xb4) */
+#define RT5616_EQ_PST_VOL_MASK			(0xffff)
+#define RT5616_EQ_PST_VOL_SFT			0
+
+/* System Clock Source */
+enum {
+	RT5616_SCLK_S_MCLK,
+	RT5616_SCLK_S_PLL1,
+};
+
+/* PLL1 Source */
+enum {
+	RT5616_PLL1_S_MCLK,
+	RT5616_PLL1_S_BCLK1,
+	RT5616_PLL1_S_BCLK2,
+};
+
+enum {
+	RT5616_AIF1,
+	RT5616_AIFS,
+};
+
+#endif /* __RT5616_H__ */
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index f2beb1a..11d032c 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -488,6 +488,18 @@
 		return 0;
 }
 
+static int is_using_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 rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+	if (!rt5640->asrc_en)
+		return 0;
+
+	return 1;
+}
+
 /* Digital Mixer */
 static const struct snd_kcontrol_new rt5640_sto_adc_l_mix[] = {
 	SOC_DAPM_SINGLE("ADC1 Switch", RT5640_STO_ADC_MIXER,
@@ -1059,6 +1071,20 @@
 static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2,
 			RT5640_PWR_PLL_BIT, 0, NULL, 0),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY_S("Stereo Filter ASRC", 1, RT5640_ASRC_1,
+			 15, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S2 Filter ASRC", 1, RT5640_ASRC_1,
+			 12, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5640_ASRC_1,
+			 11, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC1 ASRC", 1, RT5640_ASRC_1,
+			 9, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DMIC2 ASRC", 1, RT5640_ASRC_1,
+			 8, 0, NULL, 0),
+
+
 	/* Input Side */
 	/* micbias */
 	SND_SOC_DAPM_SUPPLY("LDO2", RT5640_PWR_ANLG1,
@@ -1319,6 +1345,12 @@
 };
 
 static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
+	{ "I2S1", NULL, "Stereo Filter ASRC", is_using_asrc },
+	{ "I2S2", NULL, "I2S2 ASRC", is_using_asrc },
+	{ "I2S2", NULL, "I2S2 Filter ASRC", is_using_asrc },
+	{ "DMIC1", NULL, "DMIC1 ASRC", is_using_asrc },
+	{ "DMIC2", NULL, "DMIC2 ASRC", is_using_asrc },
+
 	{"IN1P", NULL, "LDO2"},
 	{"IN2P", NULL, "LDO2"},
 	{"IN3P", NULL, "LDO2"},
@@ -1981,6 +2013,76 @@
 }
 EXPORT_SYMBOL_GPL(rt5640_dmic_enable);
 
+int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec,
+		unsigned int filter_mask, unsigned int clk_src)
+{
+	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+	unsigned int asrc2_mask = 0;
+	unsigned int asrc2_value = 0;
+
+	switch (clk_src) {
+	case RT5640_CLK_SEL_SYS:
+	case RT5640_CLK_SEL_ASRC:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (!filter_mask)
+		return -EINVAL;
+
+	if (filter_mask & RT5640_DA_STEREO_FILTER) {
+		asrc2_mask |= RT5640_STO_DAC_M_MASK;
+		asrc2_value = (asrc2_value & ~RT5640_STO_DAC_M_MASK)
+			| (clk_src << RT5640_STO_DAC_M_SFT);
+	}
+
+	if (filter_mask & RT5640_DA_MONO_L_FILTER) {
+		asrc2_mask |= RT5640_MDA_L_M_MASK;
+		asrc2_value = (asrc2_value & ~RT5640_MDA_L_M_MASK)
+			| (clk_src << RT5640_MDA_L_M_SFT);
+	}
+
+	if (filter_mask & RT5640_DA_MONO_R_FILTER) {
+		asrc2_mask |= RT5640_MDA_R_M_MASK;
+		asrc2_value = (asrc2_value & ~RT5640_MDA_R_M_MASK)
+			| (clk_src << RT5640_MDA_R_M_SFT);
+	}
+
+	if (filter_mask & RT5640_AD_STEREO_FILTER) {
+		asrc2_mask |= RT5640_ADC_M_MASK;
+		asrc2_value = (asrc2_value & ~RT5640_ADC_M_MASK)
+			| (clk_src << RT5640_ADC_M_SFT);
+	}
+
+	if (filter_mask & RT5640_AD_MONO_L_FILTER) {
+		asrc2_mask |= RT5640_MAD_L_M_MASK;
+		asrc2_value = (asrc2_value & ~RT5640_MAD_L_M_MASK)
+			| (clk_src << RT5640_MAD_L_M_SFT);
+	}
+
+	if (filter_mask & RT5640_AD_MONO_R_FILTER)  {
+		asrc2_mask |= RT5640_MAD_R_M_MASK;
+		asrc2_value = (asrc2_value & ~RT5640_MAD_R_M_MASK)
+			| (clk_src << RT5640_MAD_R_M_SFT);
+	}
+
+	snd_soc_update_bits(codec, RT5640_ASRC_2,
+		asrc2_mask, asrc2_value);
+
+	if (snd_soc_read(codec, RT5640_ASRC_2)) {
+		rt5640->asrc_en = true;
+		snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x3);
+	} else {
+		rt5640->asrc_en = false;
+		snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x0);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src);
+
 static int rt5640_probe(struct snd_soc_codec *codec)
 {
 	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
@@ -2175,6 +2277,7 @@
 	{ "INT33CA", 0 },
 	{ "10EC5640", 0 },
 	{ "10EC5642", 0 },
+	{ "INTCCFFD", 0 },
 	{ },
 };
 MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index 3deb8ba..83a7150 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -1033,6 +1033,10 @@
 #define RT5640_DMIC_2_M_NOR			(0x0 << 8)
 #define RT5640_DMIC_2_M_ASYN			(0x1 << 8)
 
+/* ASRC clock source selection (0x84) */
+#define RT5640_CLK_SEL_SYS			(0x0)
+#define RT5640_CLK_SEL_ASRC			(0x1)
+
 /* ASRC Control 2 (0x84) */
 #define RT5640_MDA_L_M_MASK			(0x1 << 15)
 #define RT5640_MDA_L_M_SFT			15
@@ -2079,6 +2083,16 @@
 	RT5640_DMIC2,
 };
 
+/* filter mask */
+enum {
+	RT5640_DA_STEREO_FILTER = 0x1,
+	RT5640_DA_MONO_L_FILTER = (0x1 << 1),
+	RT5640_DA_MONO_R_FILTER = (0x1 << 2),
+	RT5640_AD_STEREO_FILTER = (0x1 << 3),
+	RT5640_AD_MONO_L_FILTER = (0x1 << 4),
+	RT5640_AD_MONO_R_FILTER = (0x1 << 5),
+};
+
 struct rt5640_priv {
 	struct snd_soc_codec *codec;
 	struct rt5640_platform_data pdata;
@@ -2095,9 +2109,12 @@
 	int pll_out;
 
 	bool hp_mute;
+	bool asrc_en;
 };
 
 int rt5640_dmic_enable(struct snd_soc_codec *codec,
 		       bool dmic1_data_pin, bool dmic2_data_pin);
+int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec,
+		unsigned int filter_mask, unsigned int clk_src);
 
 #endif
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 3e3c7f6..c61d38b 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -64,7 +64,6 @@
 	{RT5645_PR_BASE + 0x21,	0x4040},
 	{RT5645_PR_BASE + 0x23,	0x0004},
 };
-#define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list)
 
 static const struct reg_sequence rt5650_init_list[] = {
 	{0xf6,	0x0100},
@@ -226,6 +225,163 @@
 	{ 0xff, 0x6308 },
 };
 
+static const struct reg_default rt5650_reg[] = {
+	{ 0x00, 0x0000 },
+	{ 0x01, 0xc8c8 },
+	{ 0x02, 0xc8c8 },
+	{ 0x03, 0xc8c8 },
+	{ 0x0a, 0x0002 },
+	{ 0x0b, 0x2827 },
+	{ 0x0c, 0xe000 },
+	{ 0x0d, 0x0000 },
+	{ 0x0e, 0x0000 },
+	{ 0x0f, 0x0808 },
+	{ 0x14, 0x3333 },
+	{ 0x16, 0x4b00 },
+	{ 0x18, 0x018b },
+	{ 0x19, 0xafaf },
+	{ 0x1a, 0xafaf },
+	{ 0x1b, 0x0001 },
+	{ 0x1c, 0x2f2f },
+	{ 0x1d, 0x2f2f },
+	{ 0x1e, 0x0000 },
+	{ 0x20, 0x0000 },
+	{ 0x27, 0x7060 },
+	{ 0x28, 0x7070 },
+	{ 0x29, 0x8080 },
+	{ 0x2a, 0x5656 },
+	{ 0x2b, 0x5454 },
+	{ 0x2c, 0xaaa0 },
+	{ 0x2d, 0x0000 },
+	{ 0x2f, 0x1002 },
+	{ 0x31, 0x5000 },
+	{ 0x32, 0x0000 },
+	{ 0x33, 0x0000 },
+	{ 0x34, 0x0000 },
+	{ 0x35, 0x0000 },
+	{ 0x3b, 0x0000 },
+	{ 0x3c, 0x007f },
+	{ 0x3d, 0x0000 },
+	{ 0x3e, 0x007f },
+	{ 0x3f, 0x0000 },
+	{ 0x40, 0x001f },
+	{ 0x41, 0x0000 },
+	{ 0x42, 0x001f },
+	{ 0x45, 0x6000 },
+	{ 0x46, 0x003e },
+	{ 0x47, 0x003e },
+	{ 0x48, 0xf807 },
+	{ 0x4a, 0x0004 },
+	{ 0x4d, 0x0000 },
+	{ 0x4e, 0x0000 },
+	{ 0x4f, 0x01ff },
+	{ 0x50, 0x0000 },
+	{ 0x51, 0x0000 },
+	{ 0x52, 0x01ff },
+	{ 0x53, 0xf000 },
+	{ 0x56, 0x0111 },
+	{ 0x57, 0x0064 },
+	{ 0x58, 0xef0e },
+	{ 0x59, 0xf0f0 },
+	{ 0x5a, 0xef0e },
+	{ 0x5b, 0xf0f0 },
+	{ 0x5c, 0xef0e },
+	{ 0x5d, 0xf0f0 },
+	{ 0x5e, 0xf000 },
+	{ 0x5f, 0x0000 },
+	{ 0x61, 0x0300 },
+	{ 0x62, 0x0000 },
+	{ 0x63, 0x00c2 },
+	{ 0x64, 0x0000 },
+	{ 0x65, 0x0000 },
+	{ 0x66, 0x0000 },
+	{ 0x6a, 0x0000 },
+	{ 0x6c, 0x0aaa },
+	{ 0x70, 0x8000 },
+	{ 0x71, 0x8000 },
+	{ 0x72, 0x8000 },
+	{ 0x73, 0x7770 },
+	{ 0x74, 0x3e00 },
+	{ 0x75, 0x2409 },
+	{ 0x76, 0x000a },
+	{ 0x77, 0x0c00 },
+	{ 0x78, 0x0000 },
+	{ 0x79, 0x0123 },
+	{ 0x7a, 0x0123 },
+	{ 0x80, 0x0000 },
+	{ 0x81, 0x0000 },
+	{ 0x82, 0x0000 },
+	{ 0x83, 0x0000 },
+	{ 0x84, 0x0000 },
+	{ 0x85, 0x0000 },
+	{ 0x8a, 0x0000 },
+	{ 0x8e, 0x0004 },
+	{ 0x8f, 0x1100 },
+	{ 0x90, 0x0646 },
+	{ 0x91, 0x0c06 },
+	{ 0x93, 0x0000 },
+	{ 0x94, 0x0200 },
+	{ 0x95, 0x0000 },
+	{ 0x9a, 0x2184 },
+	{ 0x9b, 0x010a },
+	{ 0x9c, 0x0aea },
+	{ 0x9d, 0x000c },
+	{ 0x9e, 0x0400 },
+	{ 0xa0, 0xa0a8 },
+	{ 0xa1, 0x0059 },
+	{ 0xa2, 0x0001 },
+	{ 0xae, 0x6000 },
+	{ 0xaf, 0x0000 },
+	{ 0xb0, 0x6000 },
+	{ 0xb1, 0x0000 },
+	{ 0xb2, 0x0000 },
+	{ 0xb3, 0x001f },
+	{ 0xb4, 0x020c },
+	{ 0xb5, 0x1f00 },
+	{ 0xb6, 0x0000 },
+	{ 0xbb, 0x0000 },
+	{ 0xbc, 0x0000 },
+	{ 0xbd, 0x0000 },
+	{ 0xbe, 0x0000 },
+	{ 0xbf, 0x3100 },
+	{ 0xc0, 0x0000 },
+	{ 0xc1, 0x0000 },
+	{ 0xc2, 0x0000 },
+	{ 0xc3, 0x2000 },
+	{ 0xcd, 0x0000 },
+	{ 0xce, 0x0000 },
+	{ 0xcf, 0x1813 },
+	{ 0xd0, 0x0690 },
+	{ 0xd1, 0x1c17 },
+	{ 0xd3, 0xb320 },
+	{ 0xd4, 0x0000 },
+	{ 0xd6, 0x0400 },
+	{ 0xd9, 0x0809 },
+	{ 0xda, 0x0000 },
+	{ 0xdb, 0x0003 },
+	{ 0xdc, 0x0049 },
+	{ 0xdd, 0x001b },
+	{ 0xdf, 0x0008 },
+	{ 0xe0, 0x4000 },
+	{ 0xe6, 0x8000 },
+	{ 0xe7, 0x0200 },
+	{ 0xec, 0xb300 },
+	{ 0xed, 0x0000 },
+	{ 0xf0, 0x001f },
+	{ 0xf1, 0x020c },
+	{ 0xf2, 0x1f00 },
+	{ 0xf3, 0x0000 },
+	{ 0xf4, 0x4000 },
+	{ 0xf8, 0x0000 },
+	{ 0xf9, 0x0000 },
+	{ 0xfa, 0x2060 },
+	{ 0xfb, 0x4040 },
+	{ 0xfc, 0x0000 },
+	{ 0xfd, 0x0002 },
+	{ 0xfe, 0x10ec },
+	{ 0xff, 0x6308 },
+};
+
 struct rt5645_eq_param_s {
 	unsigned short reg;
 	unsigned short val;
@@ -248,6 +404,7 @@
 	struct delayed_work jack_detect_work, rcclock_work;
 	struct regulator_bulk_data supplies[ARRAY_SIZE(rt5645_supply_names)];
 	struct rt5645_eq_param_s *eq_param;
+	struct timer_list btn_check_timer;
 
 	int codec_type;
 	int sysclk;
@@ -572,14 +729,12 @@
 	struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	cancel_delayed_work_sync(&rt5645->rcclock_work);
-
 	regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
 		RT5645_PWR_CLK25M_MASK, RT5645_PWR_CLK25M_PU);
 
 	ret = snd_soc_put_volsw(kcontrol, ucontrol);
 
-	queue_delayed_work(system_power_efficient_wq, &rt5645->rcclock_work,
+	mod_delayed_work(system_power_efficient_wq, &rt5645->rcclock_work,
 		msecs_to_jiffies(200));
 
 	return ret;
@@ -2911,6 +3066,7 @@
 		snd_soc_dapm_force_enable_pin(dapm, "ADC R power");
 		snd_soc_dapm_sync(dapm);
 
+		snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD1, 0x3, 0x3);
 		snd_soc_update_bits(codec,
 					RT5645_INT_IRQ_ST, 0x8, 0x8);
 		snd_soc_update_bits(codec,
@@ -2979,7 +3135,7 @@
 		}
 		if (rt5645->pdata.jd_invert)
 			regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
-				RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
+				RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR);
 	} else { /* jack out */
 		rt5645->jack_type = 0;
 
@@ -3000,7 +3156,7 @@
 		snd_soc_dapm_sync(dapm);
 		if (rt5645->pdata.jd_invert)
 			regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
-				RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR);
+				RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
 	}
 
 	return rt5645->jack_type;
@@ -3124,6 +3280,12 @@
 		}
 		if (btn_type == 0)/* button release */
 			report =  rt5645->jack_type;
+		else {
+			if (rt5645->pdata.jd_invert) {
+				mod_timer(&rt5645->btn_check_timer,
+					msecs_to_jiffies(100));
+			}
+		}
 
 		break;
 	/* jack out */
@@ -3166,6 +3328,14 @@
 	return IRQ_HANDLED;
 }
 
+static void rt5645_btn_check_callback(unsigned long data)
+{
+	struct rt5645_priv *rt5645 = (struct rt5645_priv *)data;
+
+	queue_delayed_work(system_power_efficient_wq,
+		   &rt5645->jack_detect_work, msecs_to_jiffies(5));
+}
+
 static int rt5645_probe(struct snd_soc_codec *codec)
 {
 	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
@@ -3322,6 +3492,31 @@
 	.num_ranges = ARRAY_SIZE(rt5645_ranges),
 };
 
+static const struct regmap_config rt5650_regmap = {
+	.reg_bits = 8,
+	.val_bits = 16,
+	.use_single_rw = true,
+	.max_register = RT5645_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5645_ranges) *
+					       RT5645_PR_SPACING),
+	.volatile_reg = rt5645_volatile_register,
+	.readable_reg = rt5645_readable_register,
+
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5650_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5650_reg),
+	.ranges = rt5645_ranges,
+	.num_ranges = ARRAY_SIZE(rt5645_ranges),
+};
+
+static const struct regmap_config temp_regmap = {
+	.name="nocache",
+	.reg_bits = 8,
+	.val_bits = 16,
+	.use_single_rw = true,
+	.max_register = RT5645_VENDOR_ID2 + 1,
+	.cache_type = REGCACHE_NONE,
+};
+
 static const struct i2c_device_id rt5645_i2c_id[] = {
 	{ "rt5645", 0 },
 	{ "rt5650", 0 },
@@ -3330,7 +3525,7 @@
 MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
 
 #ifdef CONFIG_ACPI
-static struct acpi_device_id rt5645_acpi_match[] = {
+static const struct acpi_device_id rt5645_acpi_match[] = {
 	{ "10EC5645", 0 },
 	{ "10EC5650", 0 },
 	{},
@@ -3338,69 +3533,23 @@
 MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
 #endif
 
-static struct rt5645_platform_data *rt5645_pdata;
-
-static struct rt5645_platform_data strago_platform_data = {
+static struct rt5645_platform_data general_platform_data = {
 	.dmic1_data_pin = RT5645_DMIC1_DISABLE,
 	.dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
 	.jd_mode = 3,
 };
 
-static int strago_quirk_cb(const struct dmi_system_id *id)
-{
-	rt5645_pdata = &strago_platform_data;
-
-	return 1;
-}
-
 static const struct dmi_system_id dmi_platform_intel_braswell[] = {
 	{
 		.ident = "Intel Strago",
-		.callback = strago_quirk_cb,
 		.matches = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "Strago"),
 		},
 	},
 	{
-		.ident = "Google Celes",
-		.callback = strago_quirk_cb,
+		.ident = "Google Chrome",
 		.matches = {
-			DMI_MATCH(DMI_PRODUCT_NAME, "Celes"),
-		},
-	},
-	{
-		.ident = "Google Ultima",
-		.callback = strago_quirk_cb,
-		.matches = {
-			DMI_MATCH(DMI_PRODUCT_NAME, "Ultima"),
-		},
-	},
-	{
-		.ident = "Google Reks",
-		.callback = strago_quirk_cb,
-		.matches = {
-			DMI_MATCH(DMI_PRODUCT_NAME, "Reks"),
-		},
-	},
-	{
-		.ident = "Google Edgar",
-		.callback = strago_quirk_cb,
-		.matches = {
-			DMI_MATCH(DMI_PRODUCT_NAME, "Edgar"),
-		},
-	},
-	{
-		.ident = "Google Wizpig",
-		.callback = strago_quirk_cb,
-		.matches = {
-			DMI_MATCH(DMI_PRODUCT_NAME, "Wizpig"),
-		},
-	},
-	{
-		.ident = "Google Terra",
-		.callback = strago_quirk_cb,
-		.matches = {
-			DMI_MATCH(DMI_PRODUCT_NAME, "Terra"),
+			DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
 		},
 	},
 	{ }
@@ -3413,17 +3562,9 @@
 	.jd_invert = true,
 };
 
-static int buddy_quirk_cb(const struct dmi_system_id *id)
-{
-	rt5645_pdata = &buddy_platform_data;
-
-	return 1;
-}
-
 static struct dmi_system_id dmi_platform_intel_broadwell[] = {
 	{
 		.ident = "Chrome Buddy",
-		.callback = buddy_quirk_cb,
 		.matches = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "Buddy"),
 		},
@@ -3431,6 +3572,16 @@
 	{ }
 };
 
+static bool rt5645_check_dp(struct device *dev)
+{
+	if (device_property_present(dev, "realtek,in2-differential") ||
+		device_property_present(dev, "realtek,dmic1-data-pin") ||
+		device_property_present(dev, "realtek,dmic2-data-pin") ||
+		device_property_present(dev, "realtek,jd-mode"))
+		return true;
+
+	return false;
+}
 
 static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev)
 {
@@ -3453,6 +3604,7 @@
 	struct rt5645_priv *rt5645;
 	int ret, i;
 	unsigned int val;
+	struct regmap *regmap;
 
 	rt5645 = devm_kzalloc(&i2c->dev, sizeof(struct rt5645_priv),
 				GFP_KERNEL);
@@ -3464,11 +3616,12 @@
 
 	if (pdata)
 		rt5645->pdata = *pdata;
-	else if (dmi_check_system(dmi_platform_intel_braswell) ||
-			dmi_check_system(dmi_platform_intel_broadwell))
-		rt5645->pdata = *rt5645_pdata;
-	else
+	else if (dmi_check_system(dmi_platform_intel_broadwell))
+		rt5645->pdata = buddy_platform_data;
+	else if (rt5645_check_dp(&i2c->dev))
 		rt5645_parse_dt(rt5645, &i2c->dev);
+	else if (dmi_check_system(dmi_platform_intel_braswell))
+		rt5645->pdata = general_platform_data;
 
 	rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect",
 						       GPIOD_IN);
@@ -3478,14 +3631,6 @@
 		return PTR_ERR(rt5645->gpiod_hp_det);
 	}
 
-	rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap);
-	if (IS_ERR(rt5645->regmap)) {
-		ret = PTR_ERR(rt5645->regmap);
-		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
-			ret);
-		return ret;
-	}
-
 	for (i = 0; i < ARRAY_SIZE(rt5645->supplies); i++)
 		rt5645->supplies[i].supply = rt5645_supply_names[i];
 
@@ -3504,13 +3649,22 @@
 		return ret;
 	}
 
-	regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val);
+	regmap = devm_regmap_init_i2c(i2c, &temp_regmap);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n",
+			ret);
+		return ret;
+	}
+	regmap_read(regmap, RT5645_VENDOR_ID2, &val);
 
 	switch (val) {
 	case RT5645_DEVICE_ID:
+		rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap);
 		rt5645->codec_type = CODEC_TYPE_RT5645;
 		break;
 	case RT5650_DEVICE_ID:
+		rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5650_regmap);
 		rt5645->codec_type = CODEC_TYPE_RT5650;
 		break;
 	default:
@@ -3521,6 +3675,13 @@
 		goto err_enable;
 	}
 
+	if (IS_ERR(rt5645->regmap)) {
+		ret = PTR_ERR(rt5645->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
 	regmap_write(rt5645->regmap, RT5645_RESET, 0);
 
 	ret = regmap_register_patch(rt5645->regmap, init_list,
@@ -3641,6 +3802,13 @@
 		}
 	}
 
+	if (rt5645->pdata.jd_invert) {
+		regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
+			RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
+		setup_timer(&rt5645->btn_check_timer,
+			rt5645_btn_check_callback, (unsigned long)rt5645);
+	}
+
 	INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
 	INIT_DELAYED_WORK(&rt5645->rcclock_work, rt5645_rcclock_work);
 
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index 1d40318..7a61970 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -18,6 +18,7 @@
 #include <linux/regmap.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>
@@ -1735,12 +1736,38 @@
 	.num_ranges = ARRAY_SIZE(rt5651_ranges),
 };
 
+#if defined(CONFIG_OF)
+static const struct of_device_id rt5651_of_match[] = {
+	{ .compatible = "realtek,rt5651", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rt5651_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5651_acpi_match[] = {
+	{ "10EC5651", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, rt5651_acpi_match);
+#endif
+
 static const struct i2c_device_id rt5651_i2c_id[] = {
 	{ "rt5651", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id);
 
+static int rt5651_parse_dt(struct rt5651_priv *rt5651, struct device_node *np)
+{
+	rt5651->pdata.in2_diff = of_property_read_bool(np,
+		"realtek,in2-differential");
+	rt5651->pdata.dmic_en = of_property_read_bool(np,
+		"realtek,dmic-en");
+
+	return 0;
+}
+
 static int rt5651_i2c_probe(struct i2c_client *i2c,
 		    const struct i2c_device_id *id)
 {
@@ -1757,6 +1784,8 @@
 
 	if (pdata)
 		rt5651->pdata = *pdata;
+	else if (i2c->dev.of_node)
+		rt5651_parse_dt(rt5651, i2c->dev.of_node);
 
 	rt5651->regmap = devm_regmap_init_i2c(i2c, &rt5651_regmap);
 	if (IS_ERR(rt5651->regmap)) {
@@ -1806,6 +1835,8 @@
 static struct i2c_driver rt5651_i2c_driver = {
 	.driver = {
 		.name = "rt5651",
+		.acpi_match_table = ACPI_PTR(rt5651_acpi_match),
+		.of_match_table = of_match_ptr(rt5651_of_match),
 	},
 	.probe = rt5651_i2c_probe,
 	.remove   = rt5651_i2c_remove,
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
new file mode 100644
index 0000000..820d8fa
--- /dev/null
+++ b/sound/soc/codecs/rt5659.c
@@ -0,0 +1,4223 @@
+/*
+ * rt5659.c  --  RT5659/RT5658 ALSA SoC audio codec driver
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@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/gpio.h>
+#include <linux/gpio/consumer.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 <sound/rt5659.h>
+
+#include "rl6231.h"
+#include "rt5659.h"
+
+static const struct reg_default rt5659_reg[] = {
+	{ 0x0000, 0x0000 },
+	{ 0x0001, 0x4848 },
+	{ 0x0002, 0x8080 },
+	{ 0x0003, 0xc8c8 },
+	{ 0x0004, 0xc80a },
+	{ 0x0005, 0x0000 },
+	{ 0x0006, 0x0000 },
+	{ 0x0007, 0x0103 },
+	{ 0x0008, 0x0080 },
+	{ 0x0009, 0x0000 },
+	{ 0x000a, 0x0000 },
+	{ 0x000c, 0x0000 },
+	{ 0x000d, 0x0000 },
+	{ 0x000f, 0x0808 },
+	{ 0x0010, 0x3080 },
+	{ 0x0011, 0x4a00 },
+	{ 0x0012, 0x4e00 },
+	{ 0x0015, 0x42c1 },
+	{ 0x0016, 0x0000 },
+	{ 0x0018, 0x000b },
+	{ 0x0019, 0xafaf },
+	{ 0x001a, 0xafaf },
+	{ 0x001b, 0x0011 },
+	{ 0x001c, 0x2f2f },
+	{ 0x001d, 0x2f2f },
+	{ 0x001e, 0x2f2f },
+	{ 0x001f, 0x0000 },
+	{ 0x0020, 0x0000 },
+	{ 0x0021, 0x0000 },
+	{ 0x0022, 0x5757 },
+	{ 0x0023, 0x0039 },
+	{ 0x0026, 0xc060 },
+	{ 0x0027, 0xd8d8 },
+	{ 0x0029, 0x8080 },
+	{ 0x002a, 0xaaaa },
+	{ 0x002b, 0xaaaa },
+	{ 0x002c, 0x00af },
+	{ 0x002d, 0x0000 },
+	{ 0x002f, 0x1002 },
+	{ 0x0031, 0x5000 },
+	{ 0x0032, 0x0000 },
+	{ 0x0033, 0x0000 },
+	{ 0x0034, 0x0000 },
+	{ 0x0035, 0x0000 },
+	{ 0x0036, 0x0000 },
+	{ 0x003a, 0x0000 },
+	{ 0x003b, 0x0000 },
+	{ 0x003c, 0x007f },
+	{ 0x003d, 0x0000 },
+	{ 0x003e, 0x007f },
+	{ 0x0040, 0x0808 },
+	{ 0x0046, 0x001f },
+	{ 0x0047, 0x001f },
+	{ 0x0048, 0x0003 },
+	{ 0x0049, 0xe061 },
+	{ 0x004a, 0x0000 },
+	{ 0x004b, 0x031f },
+	{ 0x004d, 0x0000 },
+	{ 0x004e, 0x001f },
+	{ 0x004f, 0x0000 },
+	{ 0x0050, 0x001f },
+	{ 0x0052, 0xf000 },
+	{ 0x0053, 0x0111 },
+	{ 0x0054, 0x0064 },
+	{ 0x0055, 0x0080 },
+	{ 0x0056, 0xef0e },
+	{ 0x0057, 0xf0f0 },
+	{ 0x0058, 0xef0e },
+	{ 0x0059, 0xf0f0 },
+	{ 0x005a, 0xef0e },
+	{ 0x005b, 0xf0f0 },
+	{ 0x005c, 0xf000 },
+	{ 0x005d, 0x0000 },
+	{ 0x005e, 0x1f2c },
+	{ 0x005f, 0x1f2c },
+	{ 0x0060, 0x2717 },
+	{ 0x0061, 0x0000 },
+	{ 0x0062, 0x0000 },
+	{ 0x0063, 0x003e },
+	{ 0x0064, 0x0000 },
+	{ 0x0065, 0x0000 },
+	{ 0x0066, 0x0000 },
+	{ 0x0067, 0x0000 },
+	{ 0x006a, 0x0000 },
+	{ 0x006b, 0x0000 },
+	{ 0x006c, 0x0000 },
+	{ 0x006e, 0x0000 },
+	{ 0x006f, 0x0000 },
+	{ 0x0070, 0x8000 },
+	{ 0x0071, 0x8000 },
+	{ 0x0072, 0x8000 },
+	{ 0x0073, 0x1110 },
+	{ 0x0074, 0xfe00 },
+	{ 0x0075, 0x2409 },
+	{ 0x0076, 0x000a },
+	{ 0x0077, 0x00f0 },
+	{ 0x0078, 0x0000 },
+	{ 0x0079, 0x0000 },
+	{ 0x007a, 0x0123 },
+	{ 0x007b, 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, 0x0000 },
+	{ 0x008f, 0x1000 },
+	{ 0x0090, 0x0646 },
+	{ 0x0091, 0x0c16 },
+	{ 0x0092, 0x0073 },
+	{ 0x0093, 0x0000 },
+	{ 0x0094, 0x0080 },
+	{ 0x0097, 0x0000 },
+	{ 0x0098, 0x0000 },
+	{ 0x0099, 0x0000 },
+	{ 0x009a, 0x0000 },
+	{ 0x009b, 0x0000 },
+	{ 0x009c, 0x007f },
+	{ 0x009d, 0x0000 },
+	{ 0x009e, 0x007f },
+	{ 0x009f, 0x0000 },
+	{ 0x00a0, 0x0060 },
+	{ 0x00a1, 0x90a1 },
+	{ 0x00ae, 0x2000 },
+	{ 0x00af, 0x0000 },
+	{ 0x00b0, 0x2000 },
+	{ 0x00b1, 0x0000 },
+	{ 0x00b2, 0x0000 },
+	{ 0x00b6, 0x0000 },
+	{ 0x00b7, 0x0000 },
+	{ 0x00b8, 0x0000 },
+	{ 0x00b9, 0x0000 },
+	{ 0x00ba, 0x0000 },
+	{ 0x00bb, 0x0000 },
+	{ 0x00be, 0x0000 },
+	{ 0x00bf, 0x0000 },
+	{ 0x00c0, 0x0000 },
+	{ 0x00c1, 0x0000 },
+	{ 0x00c2, 0x0000 },
+	{ 0x00c3, 0x0000 },
+	{ 0x00c4, 0x0003 },
+	{ 0x00c5, 0x0000 },
+	{ 0x00cb, 0xa02f },
+	{ 0x00cc, 0x0000 },
+	{ 0x00cd, 0x0e02 },
+	{ 0x00d6, 0x0000 },
+	{ 0x00d7, 0x2244 },
+	{ 0x00d9, 0x0809 },
+	{ 0x00da, 0x0000 },
+	{ 0x00db, 0x0008 },
+	{ 0x00dc, 0x00c0 },
+	{ 0x00dd, 0x6724 },
+	{ 0x00de, 0x3131 },
+	{ 0x00df, 0x0008 },
+	{ 0x00e0, 0x4000 },
+	{ 0x00e1, 0x3131 },
+	{ 0x00e4, 0x400c },
+	{ 0x00e5, 0x8031 },
+	{ 0x00ea, 0xb320 },
+	{ 0x00eb, 0x0000 },
+	{ 0x00ec, 0xb300 },
+	{ 0x00ed, 0x0000 },
+	{ 0x00f0, 0x0000 },
+	{ 0x00f1, 0x0202 },
+	{ 0x00f2, 0x0ddd },
+	{ 0x00f3, 0x0ddd },
+	{ 0x00f4, 0x0ddd },
+	{ 0x00f6, 0x0000 },
+	{ 0x00f7, 0x0000 },
+	{ 0x00f8, 0x0000 },
+	{ 0x00f9, 0x0000 },
+	{ 0x00fa, 0x8000 },
+	{ 0x00fb, 0x0000 },
+	{ 0x00fc, 0x0000 },
+	{ 0x00fd, 0x0001 },
+	{ 0x00fe, 0x10ec },
+	{ 0x00ff, 0x6311 },
+	{ 0x0100, 0xaaaa },
+	{ 0x010a, 0xaaaa },
+	{ 0x010b, 0x00a0 },
+	{ 0x010c, 0xaeae },
+	{ 0x010d, 0xaaaa },
+	{ 0x010e, 0xaaa8 },
+	{ 0x010f, 0xa0aa },
+	{ 0x0110, 0xe02a },
+	{ 0x0111, 0xa702 },
+	{ 0x0112, 0xaaaa },
+	{ 0x0113, 0x2800 },
+	{ 0x0116, 0x0000 },
+	{ 0x0117, 0x0f00 },
+	{ 0x011a, 0x0020 },
+	{ 0x011b, 0x0011 },
+	{ 0x011c, 0x0150 },
+	{ 0x011d, 0x0000 },
+	{ 0x011e, 0x0000 },
+	{ 0x011f, 0x0000 },
+	{ 0x0120, 0x0000 },
+	{ 0x0121, 0x009b },
+	{ 0x0122, 0x5014 },
+	{ 0x0123, 0x0421 },
+	{ 0x0124, 0x7cea },
+	{ 0x0125, 0x0420 },
+	{ 0x0126, 0x5550 },
+	{ 0x0132, 0x0000 },
+	{ 0x0133, 0x0000 },
+	{ 0x0137, 0x5055 },
+	{ 0x0138, 0x3700 },
+	{ 0x0139, 0x79a1 },
+	{ 0x013a, 0x2020 },
+	{ 0x013b, 0x2020 },
+	{ 0x013c, 0x2005 },
+	{ 0x013e, 0x1f00 },
+	{ 0x013f, 0x0000 },
+	{ 0x0145, 0x0002 },
+	{ 0x0146, 0x0000 },
+	{ 0x0147, 0x0000 },
+	{ 0x0148, 0x0000 },
+	{ 0x0150, 0x1813 },
+	{ 0x0151, 0x0690 },
+	{ 0x0152, 0x1c17 },
+	{ 0x0153, 0x6883 },
+	{ 0x0154, 0xd3ce },
+	{ 0x0155, 0x352d },
+	{ 0x0156, 0x00eb },
+	{ 0x0157, 0x3717 },
+	{ 0x0158, 0x4c6a },
+	{ 0x0159, 0xe41b },
+	{ 0x015a, 0x2a13 },
+	{ 0x015b, 0xb600 },
+	{ 0x015c, 0xc730 },
+	{ 0x015d, 0x35d4 },
+	{ 0x015e, 0x00bf },
+	{ 0x0160, 0x0ec0 },
+	{ 0x0161, 0x0020 },
+	{ 0x0162, 0x0080 },
+	{ 0x0163, 0x0800 },
+	{ 0x0164, 0x0000 },
+	{ 0x0165, 0x0000 },
+	{ 0x0166, 0x0000 },
+	{ 0x0167, 0x001f },
+	{ 0x0170, 0x4e80 },
+	{ 0x0171, 0x0020 },
+	{ 0x0172, 0x0080 },
+	{ 0x0173, 0x0800 },
+	{ 0x0174, 0x000c },
+	{ 0x0175, 0x0000 },
+	{ 0x0190, 0x3300 },
+	{ 0x0191, 0x2200 },
+	{ 0x0192, 0x0000 },
+	{ 0x01b0, 0x4b38 },
+	{ 0x01b1, 0x0000 },
+	{ 0x01b2, 0x0000 },
+	{ 0x01b3, 0x0000 },
+	{ 0x01c0, 0x0045 },
+	{ 0x01c1, 0x0540 },
+	{ 0x01c2, 0x0000 },
+	{ 0x01c3, 0x0030 },
+	{ 0x01c7, 0x0000 },
+	{ 0x01c8, 0x5757 },
+	{ 0x01c9, 0x5757 },
+	{ 0x01ca, 0x5757 },
+	{ 0x01cb, 0x5757 },
+	{ 0x01cc, 0x5757 },
+	{ 0x01cd, 0x5757 },
+	{ 0x01ce, 0x006f },
+	{ 0x01da, 0x0000 },
+	{ 0x01db, 0x0000 },
+	{ 0x01de, 0x7d00 },
+	{ 0x01df, 0x10c0 },
+	{ 0x01e0, 0x06a1 },
+	{ 0x01e1, 0x0000 },
+	{ 0x01e2, 0x0000 },
+	{ 0x01e3, 0x0000 },
+	{ 0x01e4, 0x0001 },
+	{ 0x01e6, 0x0000 },
+	{ 0x01e7, 0x0000 },
+	{ 0x01e8, 0x0000 },
+	{ 0x01ea, 0x0000 },
+	{ 0x01eb, 0x0000 },
+	{ 0x01ec, 0x0000 },
+	{ 0x01ed, 0x0000 },
+	{ 0x01ee, 0x0000 },
+	{ 0x01ef, 0x0000 },
+	{ 0x01f0, 0x0000 },
+	{ 0x01f1, 0x0000 },
+	{ 0x01f2, 0x0000 },
+	{ 0x01f6, 0x1e04 },
+	{ 0x01f7, 0x01a1 },
+	{ 0x01f8, 0x0000 },
+	{ 0x01f9, 0x0000 },
+	{ 0x01fa, 0x0002 },
+	{ 0x01fb, 0x0000 },
+	{ 0x01fc, 0x0000 },
+	{ 0x01fd, 0x0000 },
+	{ 0x01fe, 0x0000 },
+	{ 0x0200, 0x066c },
+	{ 0x0201, 0x7fff },
+	{ 0x0202, 0x7fff },
+	{ 0x0203, 0x0000 },
+	{ 0x0204, 0x0000 },
+	{ 0x0205, 0x0000 },
+	{ 0x0206, 0x0000 },
+	{ 0x0207, 0x0000 },
+	{ 0x0208, 0x0000 },
+	{ 0x0256, 0x0000 },
+	{ 0x0257, 0x0000 },
+	{ 0x0258, 0x0000 },
+	{ 0x0259, 0x0000 },
+	{ 0x025a, 0x0000 },
+	{ 0x025b, 0x3333 },
+	{ 0x025c, 0x3333 },
+	{ 0x025d, 0x3333 },
+	{ 0x025e, 0x0000 },
+	{ 0x025f, 0x0000 },
+	{ 0x0260, 0x0000 },
+	{ 0x0261, 0x0022 },
+	{ 0x0262, 0x0300 },
+	{ 0x0265, 0x1e80 },
+	{ 0x0266, 0x0131 },
+	{ 0x0267, 0x0003 },
+	{ 0x0268, 0x0000 },
+	{ 0x0269, 0x0000 },
+	{ 0x026a, 0x0000 },
+	{ 0x026b, 0x0000 },
+	{ 0x026c, 0x0000 },
+	{ 0x026d, 0x0000 },
+	{ 0x026e, 0x0000 },
+	{ 0x026f, 0x0000 },
+	{ 0x0270, 0x0000 },
+	{ 0x0271, 0x0000 },
+	{ 0x0272, 0x0000 },
+	{ 0x0273, 0x0000 },
+	{ 0x0280, 0x0000 },
+	{ 0x0281, 0x0000 },
+	{ 0x0282, 0x0418 },
+	{ 0x0283, 0x7fff },
+	{ 0x0284, 0x7000 },
+	{ 0x0290, 0x01d0 },
+	{ 0x0291, 0x0100 },
+	{ 0x02fa, 0x0000 },
+	{ 0x02fb, 0x0000 },
+	{ 0x02fc, 0x0000 },
+	{ 0x0300, 0x001f },
+	{ 0x0301, 0x032c },
+	{ 0x0302, 0x5f21 },
+	{ 0x0303, 0x4000 },
+	{ 0x0304, 0x4000 },
+	{ 0x0305, 0x0600 },
+	{ 0x0306, 0x8000 },
+	{ 0x0307, 0x0700 },
+	{ 0x0308, 0x001f },
+	{ 0x0309, 0x032c },
+	{ 0x030a, 0x5f21 },
+	{ 0x030b, 0x4000 },
+	{ 0x030c, 0x4000 },
+	{ 0x030d, 0x0600 },
+	{ 0x030e, 0x8000 },
+	{ 0x030f, 0x0700 },
+	{ 0x0310, 0x4560 },
+	{ 0x0311, 0xa4a8 },
+	{ 0x0312, 0x7418 },
+	{ 0x0313, 0x0000 },
+	{ 0x0314, 0x0006 },
+	{ 0x0315, 0x00ff },
+	{ 0x0316, 0xc400 },
+	{ 0x0317, 0x4560 },
+	{ 0x0318, 0xa4a8 },
+	{ 0x0319, 0x7418 },
+	{ 0x031a, 0x0000 },
+	{ 0x031b, 0x0006 },
+	{ 0x031c, 0x00ff },
+	{ 0x031d, 0xc400 },
+	{ 0x0320, 0x0f20 },
+	{ 0x0321, 0x8700 },
+	{ 0x0322, 0x7dc2 },
+	{ 0x0323, 0xa178 },
+	{ 0x0324, 0x5383 },
+	{ 0x0325, 0x7dc2 },
+	{ 0x0326, 0xa178 },
+	{ 0x0327, 0x5383 },
+	{ 0x0328, 0x003e },
+	{ 0x0329, 0x02c1 },
+	{ 0x032a, 0xd37d },
+	{ 0x0330, 0x00a6 },
+	{ 0x0331, 0x04c3 },
+	{ 0x0332, 0x27c8 },
+	{ 0x0333, 0xbf50 },
+	{ 0x0334, 0x0045 },
+	{ 0x0335, 0x2007 },
+	{ 0x0336, 0x7418 },
+	{ 0x0337, 0x0501 },
+	{ 0x0338, 0x0000 },
+	{ 0x0339, 0x0010 },
+	{ 0x033a, 0x1010 },
+	{ 0x0340, 0x0800 },
+	{ 0x0341, 0x0800 },
+	{ 0x0342, 0x0800 },
+	{ 0x0343, 0x0800 },
+	{ 0x0344, 0x0000 },
+	{ 0x0345, 0x0000 },
+	{ 0x0346, 0x0000 },
+	{ 0x0347, 0x0000 },
+	{ 0x0348, 0x0000 },
+	{ 0x0349, 0x0000 },
+	{ 0x034a, 0x0000 },
+	{ 0x034b, 0x0000 },
+	{ 0x034c, 0x0000 },
+	{ 0x034d, 0x0000 },
+	{ 0x034e, 0x0000 },
+	{ 0x034f, 0x0000 },
+	{ 0x0350, 0x0000 },
+	{ 0x0351, 0x0000 },
+	{ 0x0352, 0x0000 },
+	{ 0x0353, 0x0000 },
+	{ 0x0354, 0x0000 },
+	{ 0x0355, 0x0000 },
+	{ 0x0356, 0x0000 },
+	{ 0x0357, 0x0000 },
+	{ 0x0358, 0x0000 },
+	{ 0x0359, 0x0000 },
+	{ 0x035a, 0x0000 },
+	{ 0x035b, 0x0000 },
+	{ 0x035c, 0x0000 },
+	{ 0x035d, 0x0000 },
+	{ 0x035e, 0x2000 },
+	{ 0x035f, 0x0000 },
+	{ 0x0360, 0x2000 },
+	{ 0x0361, 0x2000 },
+	{ 0x0362, 0x0000 },
+	{ 0x0363, 0x2000 },
+	{ 0x0364, 0x0200 },
+	{ 0x0365, 0x0000 },
+	{ 0x0366, 0x0000 },
+	{ 0x0367, 0x0000 },
+	{ 0x0368, 0x0000 },
+	{ 0x0369, 0x0000 },
+	{ 0x036a, 0x0000 },
+	{ 0x036b, 0x0000 },
+	{ 0x036c, 0x0000 },
+	{ 0x036d, 0x0000 },
+	{ 0x036e, 0x0200 },
+	{ 0x036f, 0x0000 },
+	{ 0x0370, 0x0000 },
+	{ 0x0371, 0x0000 },
+	{ 0x0372, 0x0000 },
+	{ 0x0373, 0x0000 },
+	{ 0x0374, 0x0000 },
+	{ 0x0375, 0x0000 },
+	{ 0x0376, 0x0000 },
+	{ 0x0377, 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 rt5659_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5659_RESET:
+	case RT5659_EJD_CTRL_2:
+	case RT5659_SILENCE_CTRL:
+	case RT5659_DAC2_DIG_VOL:
+	case RT5659_HP_IMP_GAIN_2:
+	case RT5659_PDM_OUT_CTRL:
+	case RT5659_PDM_DATA_CTRL_1:
+	case RT5659_PDM_DATA_CTRL_4:
+	case RT5659_HAPTIC_GEN_CTRL_1:
+	case RT5659_HAPTIC_GEN_CTRL_3:
+	case RT5659_HAPTIC_LPF_CTRL_3:
+	case RT5659_CLK_DET:
+	case RT5659_MICBIAS_1:
+	case RT5659_ASRC_11:
+	case RT5659_ADC_EQ_CTRL_1:
+	case RT5659_DAC_EQ_CTRL_1:
+	case RT5659_INT_ST_1:
+	case RT5659_INT_ST_2:
+	case RT5659_GPIO_STA:
+	case RT5659_SINE_GEN_CTRL_1:
+	case RT5659_IL_CMD_1:
+	case RT5659_4BTN_IL_CMD_1:
+	case RT5659_PSV_IL_CMD_1:
+	case RT5659_AJD1_CTRL:
+	case RT5659_AJD2_AJD3_CTRL:
+	case RT5659_JD_CTRL_3:
+	case RT5659_VENDOR_ID:
+	case RT5659_VENDOR_ID_1:
+	case RT5659_DEVICE_ID:
+	case RT5659_MEMORY_TEST:
+	case RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL:
+	case RT5659_VOL_TEST:
+	case RT5659_STO_NG2_CTRL_1:
+	case RT5659_STO_NG2_CTRL_5:
+	case RT5659_STO_NG2_CTRL_6:
+	case RT5659_STO_NG2_CTRL_7:
+	case RT5659_MONO_NG2_CTRL_1:
+	case RT5659_MONO_NG2_CTRL_5:
+	case RT5659_MONO_NG2_CTRL_6:
+	case RT5659_HP_IMP_SENS_CTRL_1:
+	case RT5659_HP_IMP_SENS_CTRL_3:
+	case RT5659_HP_IMP_SENS_CTRL_4:
+	case RT5659_HP_CALIB_CTRL_1:
+	case RT5659_HP_CALIB_CTRL_9:
+	case RT5659_HP_CALIB_STA_1:
+	case RT5659_HP_CALIB_STA_2:
+	case RT5659_HP_CALIB_STA_3:
+	case RT5659_HP_CALIB_STA_4:
+	case RT5659_HP_CALIB_STA_5:
+	case RT5659_HP_CALIB_STA_6:
+	case RT5659_HP_CALIB_STA_7:
+	case RT5659_HP_CALIB_STA_8:
+	case RT5659_HP_CALIB_STA_9:
+	case RT5659_MONO_AMP_CALIB_CTRL_1:
+	case RT5659_MONO_AMP_CALIB_CTRL_3:
+	case RT5659_MONO_AMP_CALIB_STA_1:
+	case RT5659_MONO_AMP_CALIB_STA_2:
+	case RT5659_MONO_AMP_CALIB_STA_3:
+	case RT5659_MONO_AMP_CALIB_STA_4:
+	case RT5659_SPK_PWR_LMT_STA_1:
+	case RT5659_SPK_PWR_LMT_STA_2:
+	case RT5659_SPK_PWR_LMT_STA_3:
+	case RT5659_SPK_PWR_LMT_STA_4:
+	case RT5659_SPK_PWR_LMT_STA_5:
+	case RT5659_SPK_PWR_LMT_STA_6:
+	case RT5659_SPK_DC_CAILB_CTRL_1:
+	case RT5659_SPK_DC_CAILB_STA_1:
+	case RT5659_SPK_DC_CAILB_STA_2:
+	case RT5659_SPK_DC_CAILB_STA_3:
+	case RT5659_SPK_DC_CAILB_STA_4:
+	case RT5659_SPK_DC_CAILB_STA_5:
+	case RT5659_SPK_DC_CAILB_STA_6:
+	case RT5659_SPK_DC_CAILB_STA_7:
+	case RT5659_SPK_DC_CAILB_STA_8:
+	case RT5659_SPK_DC_CAILB_STA_9:
+	case RT5659_SPK_DC_CAILB_STA_10:
+	case RT5659_SPK_VDD_STA_1:
+	case RT5659_SPK_VDD_STA_2:
+	case RT5659_SPK_DC_DET_CTRL_1:
+	case RT5659_PURE_DC_DET_CTRL_1:
+	case RT5659_PURE_DC_DET_CTRL_2:
+	case RT5659_DRC1_PRIV_1:
+	case RT5659_DRC1_PRIV_4:
+	case RT5659_DRC1_PRIV_5:
+	case RT5659_DRC1_PRIV_6:
+	case RT5659_DRC1_PRIV_7:
+	case RT5659_DRC2_PRIV_1:
+	case RT5659_DRC2_PRIV_4:
+	case RT5659_DRC2_PRIV_5:
+	case RT5659_DRC2_PRIV_6:
+	case RT5659_DRC2_PRIV_7:
+	case RT5659_ALC_PGA_STA_1:
+	case RT5659_ALC_PGA_STA_2:
+	case RT5659_ALC_PGA_STA_3:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool rt5659_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case RT5659_RESET:
+	case RT5659_SPO_VOL:
+	case RT5659_HP_VOL:
+	case RT5659_LOUT:
+	case RT5659_MONO_OUT:
+	case RT5659_HPL_GAIN:
+	case RT5659_HPR_GAIN:
+	case RT5659_MONO_GAIN:
+	case RT5659_SPDIF_CTRL_1:
+	case RT5659_SPDIF_CTRL_2:
+	case RT5659_CAL_BST_CTRL:
+	case RT5659_IN1_IN2:
+	case RT5659_IN3_IN4:
+	case RT5659_INL1_INR1_VOL:
+	case RT5659_EJD_CTRL_1:
+	case RT5659_EJD_CTRL_2:
+	case RT5659_EJD_CTRL_3:
+	case RT5659_SILENCE_CTRL:
+	case RT5659_PSV_CTRL:
+	case RT5659_SIDETONE_CTRL:
+	case RT5659_DAC1_DIG_VOL:
+	case RT5659_DAC2_DIG_VOL:
+	case RT5659_DAC_CTRL:
+	case RT5659_STO1_ADC_DIG_VOL:
+	case RT5659_MONO_ADC_DIG_VOL:
+	case RT5659_STO2_ADC_DIG_VOL:
+	case RT5659_STO1_BOOST:
+	case RT5659_MONO_BOOST:
+	case RT5659_STO2_BOOST:
+	case RT5659_HP_IMP_GAIN_1:
+	case RT5659_HP_IMP_GAIN_2:
+	case RT5659_STO1_ADC_MIXER:
+	case RT5659_MONO_ADC_MIXER:
+	case RT5659_AD_DA_MIXER:
+	case RT5659_STO_DAC_MIXER:
+	case RT5659_MONO_DAC_MIXER:
+	case RT5659_DIG_MIXER:
+	case RT5659_A_DAC_MUX:
+	case RT5659_DIG_INF23_DATA:
+	case RT5659_PDM_OUT_CTRL:
+	case RT5659_PDM_DATA_CTRL_1:
+	case RT5659_PDM_DATA_CTRL_2:
+	case RT5659_PDM_DATA_CTRL_3:
+	case RT5659_PDM_DATA_CTRL_4:
+	case RT5659_SPDIF_CTRL:
+	case RT5659_REC1_GAIN:
+	case RT5659_REC1_L1_MIXER:
+	case RT5659_REC1_L2_MIXER:
+	case RT5659_REC1_R1_MIXER:
+	case RT5659_REC1_R2_MIXER:
+	case RT5659_CAL_REC:
+	case RT5659_REC2_L1_MIXER:
+	case RT5659_REC2_L2_MIXER:
+	case RT5659_REC2_R1_MIXER:
+	case RT5659_REC2_R2_MIXER:
+	case RT5659_SPK_L_MIXER:
+	case RT5659_SPK_R_MIXER:
+	case RT5659_SPO_AMP_GAIN:
+	case RT5659_ALC_BACK_GAIN:
+	case RT5659_MONOMIX_GAIN:
+	case RT5659_MONOMIX_IN_GAIN:
+	case RT5659_OUT_L_GAIN:
+	case RT5659_OUT_L_MIXER:
+	case RT5659_OUT_R_GAIN:
+	case RT5659_OUT_R_MIXER:
+	case RT5659_LOUT_MIXER:
+	case RT5659_HAPTIC_GEN_CTRL_1:
+	case RT5659_HAPTIC_GEN_CTRL_2:
+	case RT5659_HAPTIC_GEN_CTRL_3:
+	case RT5659_HAPTIC_GEN_CTRL_4:
+	case RT5659_HAPTIC_GEN_CTRL_5:
+	case RT5659_HAPTIC_GEN_CTRL_6:
+	case RT5659_HAPTIC_GEN_CTRL_7:
+	case RT5659_HAPTIC_GEN_CTRL_8:
+	case RT5659_HAPTIC_GEN_CTRL_9:
+	case RT5659_HAPTIC_GEN_CTRL_10:
+	case RT5659_HAPTIC_GEN_CTRL_11:
+	case RT5659_HAPTIC_LPF_CTRL_1:
+	case RT5659_HAPTIC_LPF_CTRL_2:
+	case RT5659_HAPTIC_LPF_CTRL_3:
+	case RT5659_PWR_DIG_1:
+	case RT5659_PWR_DIG_2:
+	case RT5659_PWR_ANLG_1:
+	case RT5659_PWR_ANLG_2:
+	case RT5659_PWR_ANLG_3:
+	case RT5659_PWR_MIXER:
+	case RT5659_PWR_VOL:
+	case RT5659_PRIV_INDEX:
+	case RT5659_CLK_DET:
+	case RT5659_PRIV_DATA:
+	case RT5659_PRE_DIV_1:
+	case RT5659_PRE_DIV_2:
+	case RT5659_I2S1_SDP:
+	case RT5659_I2S2_SDP:
+	case RT5659_I2S3_SDP:
+	case RT5659_ADDA_CLK_1:
+	case RT5659_ADDA_CLK_2:
+	case RT5659_DMIC_CTRL_1:
+	case RT5659_DMIC_CTRL_2:
+	case RT5659_TDM_CTRL_1:
+	case RT5659_TDM_CTRL_2:
+	case RT5659_TDM_CTRL_3:
+	case RT5659_TDM_CTRL_4:
+	case RT5659_TDM_CTRL_5:
+	case RT5659_GLB_CLK:
+	case RT5659_PLL_CTRL_1:
+	case RT5659_PLL_CTRL_2:
+	case RT5659_ASRC_1:
+	case RT5659_ASRC_2:
+	case RT5659_ASRC_3:
+	case RT5659_ASRC_4:
+	case RT5659_ASRC_5:
+	case RT5659_ASRC_6:
+	case RT5659_ASRC_7:
+	case RT5659_ASRC_8:
+	case RT5659_ASRC_9:
+	case RT5659_ASRC_10:
+	case RT5659_DEPOP_1:
+	case RT5659_DEPOP_2:
+	case RT5659_DEPOP_3:
+	case RT5659_HP_CHARGE_PUMP_1:
+	case RT5659_HP_CHARGE_PUMP_2:
+	case RT5659_MICBIAS_1:
+	case RT5659_MICBIAS_2:
+	case RT5659_ASRC_11:
+	case RT5659_ASRC_12:
+	case RT5659_ASRC_13:
+	case RT5659_REC_M1_M2_GAIN_CTRL:
+	case RT5659_RC_CLK_CTRL:
+	case RT5659_CLASSD_CTRL_1:
+	case RT5659_CLASSD_CTRL_2:
+	case RT5659_ADC_EQ_CTRL_1:
+	case RT5659_ADC_EQ_CTRL_2:
+	case RT5659_DAC_EQ_CTRL_1:
+	case RT5659_DAC_EQ_CTRL_2:
+	case RT5659_DAC_EQ_CTRL_3:
+	case RT5659_IRQ_CTRL_1:
+	case RT5659_IRQ_CTRL_2:
+	case RT5659_IRQ_CTRL_3:
+	case RT5659_IRQ_CTRL_4:
+	case RT5659_IRQ_CTRL_5:
+	case RT5659_IRQ_CTRL_6:
+	case RT5659_INT_ST_1:
+	case RT5659_INT_ST_2:
+	case RT5659_GPIO_CTRL_1:
+	case RT5659_GPIO_CTRL_2:
+	case RT5659_GPIO_CTRL_3:
+	case RT5659_GPIO_CTRL_4:
+	case RT5659_GPIO_CTRL_5:
+	case RT5659_GPIO_STA:
+	case RT5659_SINE_GEN_CTRL_1:
+	case RT5659_SINE_GEN_CTRL_2:
+	case RT5659_SINE_GEN_CTRL_3:
+	case RT5659_HP_AMP_DET_CTRL_1:
+	case RT5659_HP_AMP_DET_CTRL_2:
+	case RT5659_SV_ZCD_1:
+	case RT5659_SV_ZCD_2:
+	case RT5659_IL_CMD_1:
+	case RT5659_IL_CMD_2:
+	case RT5659_IL_CMD_3:
+	case RT5659_IL_CMD_4:
+	case RT5659_4BTN_IL_CMD_1:
+	case RT5659_4BTN_IL_CMD_2:
+	case RT5659_4BTN_IL_CMD_3:
+	case RT5659_PSV_IL_CMD_1:
+	case RT5659_PSV_IL_CMD_2:
+	case RT5659_ADC_STO1_HP_CTRL_1:
+	case RT5659_ADC_STO1_HP_CTRL_2:
+	case RT5659_ADC_MONO_HP_CTRL_1:
+	case RT5659_ADC_MONO_HP_CTRL_2:
+	case RT5659_AJD1_CTRL:
+	case RT5659_AJD2_AJD3_CTRL:
+	case RT5659_JD1_THD:
+	case RT5659_JD2_THD:
+	case RT5659_JD3_THD:
+	case RT5659_JD_CTRL_1:
+	case RT5659_JD_CTRL_2:
+	case RT5659_JD_CTRL_3:
+	case RT5659_JD_CTRL_4:
+	case RT5659_DIG_MISC:
+	case RT5659_DUMMY_2:
+	case RT5659_DUMMY_3:
+	case RT5659_VENDOR_ID:
+	case RT5659_VENDOR_ID_1:
+	case RT5659_DEVICE_ID:
+	case RT5659_DAC_ADC_DIG_VOL:
+	case RT5659_BIAS_CUR_CTRL_1:
+	case RT5659_BIAS_CUR_CTRL_2:
+	case RT5659_BIAS_CUR_CTRL_3:
+	case RT5659_BIAS_CUR_CTRL_4:
+	case RT5659_BIAS_CUR_CTRL_5:
+	case RT5659_BIAS_CUR_CTRL_6:
+	case RT5659_BIAS_CUR_CTRL_7:
+	case RT5659_BIAS_CUR_CTRL_8:
+	case RT5659_BIAS_CUR_CTRL_9:
+	case RT5659_BIAS_CUR_CTRL_10:
+	case RT5659_MEMORY_TEST:
+	case RT5659_VREF_REC_OP_FB_CAP_CTRL:
+	case RT5659_CLASSD_0:
+	case RT5659_CLASSD_1:
+	case RT5659_CLASSD_2:
+	case RT5659_CLASSD_3:
+	case RT5659_CLASSD_4:
+	case RT5659_CLASSD_5:
+	case RT5659_CLASSD_6:
+	case RT5659_CLASSD_7:
+	case RT5659_CLASSD_8:
+	case RT5659_CLASSD_9:
+	case RT5659_CLASSD_10:
+	case RT5659_CHARGE_PUMP_1:
+	case RT5659_CHARGE_PUMP_2:
+	case RT5659_DIG_IN_CTRL_1:
+	case RT5659_DIG_IN_CTRL_2:
+	case RT5659_PAD_DRIVING_CTRL:
+	case RT5659_SOFT_RAMP_DEPOP:
+	case RT5659_PLL:
+	case RT5659_CHOP_DAC:
+	case RT5659_CHOP_ADC:
+	case RT5659_CALIB_ADC_CTRL:
+	case RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL:
+	case RT5659_VOL_TEST:
+	case RT5659_TEST_MODE_CTRL_1:
+	case RT5659_TEST_MODE_CTRL_2:
+	case RT5659_TEST_MODE_CTRL_3:
+	case RT5659_TEST_MODE_CTRL_4:
+	case RT5659_BASSBACK_CTRL:
+	case RT5659_MP3_PLUS_CTRL_1:
+	case RT5659_MP3_PLUS_CTRL_2:
+	case RT5659_MP3_HPF_A1:
+	case RT5659_MP3_HPF_A2:
+	case RT5659_MP3_HPF_H0:
+	case RT5659_MP3_LPF_H0:
+	case RT5659_3D_SPK_CTRL:
+	case RT5659_3D_SPK_COEF_1:
+	case RT5659_3D_SPK_COEF_2:
+	case RT5659_3D_SPK_COEF_3:
+	case RT5659_3D_SPK_COEF_4:
+	case RT5659_3D_SPK_COEF_5:
+	case RT5659_3D_SPK_COEF_6:
+	case RT5659_3D_SPK_COEF_7:
+	case RT5659_STO_NG2_CTRL_1:
+	case RT5659_STO_NG2_CTRL_2:
+	case RT5659_STO_NG2_CTRL_3:
+	case RT5659_STO_NG2_CTRL_4:
+	case RT5659_STO_NG2_CTRL_5:
+	case RT5659_STO_NG2_CTRL_6:
+	case RT5659_STO_NG2_CTRL_7:
+	case RT5659_STO_NG2_CTRL_8:
+	case RT5659_MONO_NG2_CTRL_1:
+	case RT5659_MONO_NG2_CTRL_2:
+	case RT5659_MONO_NG2_CTRL_3:
+	case RT5659_MONO_NG2_CTRL_4:
+	case RT5659_MONO_NG2_CTRL_5:
+	case RT5659_MONO_NG2_CTRL_6:
+	case RT5659_MID_HP_AMP_DET:
+	case RT5659_LOW_HP_AMP_DET:
+	case RT5659_LDO_CTRL:
+	case RT5659_HP_DECROSS_CTRL_1:
+	case RT5659_HP_DECROSS_CTRL_2:
+	case RT5659_HP_DECROSS_CTRL_3:
+	case RT5659_HP_DECROSS_CTRL_4:
+	case RT5659_HP_IMP_SENS_CTRL_1:
+	case RT5659_HP_IMP_SENS_CTRL_2:
+	case RT5659_HP_IMP_SENS_CTRL_3:
+	case RT5659_HP_IMP_SENS_CTRL_4:
+	case RT5659_HP_IMP_SENS_MAP_1:
+	case RT5659_HP_IMP_SENS_MAP_2:
+	case RT5659_HP_IMP_SENS_MAP_3:
+	case RT5659_HP_IMP_SENS_MAP_4:
+	case RT5659_HP_IMP_SENS_MAP_5:
+	case RT5659_HP_IMP_SENS_MAP_6:
+	case RT5659_HP_IMP_SENS_MAP_7:
+	case RT5659_HP_IMP_SENS_MAP_8:
+	case RT5659_HP_LOGIC_CTRL_1:
+	case RT5659_HP_LOGIC_CTRL_2:
+	case RT5659_HP_CALIB_CTRL_1:
+	case RT5659_HP_CALIB_CTRL_2:
+	case RT5659_HP_CALIB_CTRL_3:
+	case RT5659_HP_CALIB_CTRL_4:
+	case RT5659_HP_CALIB_CTRL_5:
+	case RT5659_HP_CALIB_CTRL_6:
+	case RT5659_HP_CALIB_CTRL_7:
+	case RT5659_HP_CALIB_CTRL_9:
+	case RT5659_HP_CALIB_CTRL_10:
+	case RT5659_HP_CALIB_CTRL_11:
+	case RT5659_HP_CALIB_STA_1:
+	case RT5659_HP_CALIB_STA_2:
+	case RT5659_HP_CALIB_STA_3:
+	case RT5659_HP_CALIB_STA_4:
+	case RT5659_HP_CALIB_STA_5:
+	case RT5659_HP_CALIB_STA_6:
+	case RT5659_HP_CALIB_STA_7:
+	case RT5659_HP_CALIB_STA_8:
+	case RT5659_HP_CALIB_STA_9:
+	case RT5659_MONO_AMP_CALIB_CTRL_1:
+	case RT5659_MONO_AMP_CALIB_CTRL_2:
+	case RT5659_MONO_AMP_CALIB_CTRL_3:
+	case RT5659_MONO_AMP_CALIB_CTRL_4:
+	case RT5659_MONO_AMP_CALIB_CTRL_5:
+	case RT5659_MONO_AMP_CALIB_STA_1:
+	case RT5659_MONO_AMP_CALIB_STA_2:
+	case RT5659_MONO_AMP_CALIB_STA_3:
+	case RT5659_MONO_AMP_CALIB_STA_4:
+	case RT5659_SPK_PWR_LMT_CTRL_1:
+	case RT5659_SPK_PWR_LMT_CTRL_2:
+	case RT5659_SPK_PWR_LMT_CTRL_3:
+	case RT5659_SPK_PWR_LMT_STA_1:
+	case RT5659_SPK_PWR_LMT_STA_2:
+	case RT5659_SPK_PWR_LMT_STA_3:
+	case RT5659_SPK_PWR_LMT_STA_4:
+	case RT5659_SPK_PWR_LMT_STA_5:
+	case RT5659_SPK_PWR_LMT_STA_6:
+	case RT5659_FLEX_SPK_BST_CTRL_1:
+	case RT5659_FLEX_SPK_BST_CTRL_2:
+	case RT5659_FLEX_SPK_BST_CTRL_3:
+	case RT5659_FLEX_SPK_BST_CTRL_4:
+	case RT5659_SPK_EX_LMT_CTRL_1:
+	case RT5659_SPK_EX_LMT_CTRL_2:
+	case RT5659_SPK_EX_LMT_CTRL_3:
+	case RT5659_SPK_EX_LMT_CTRL_4:
+	case RT5659_SPK_EX_LMT_CTRL_5:
+	case RT5659_SPK_EX_LMT_CTRL_6:
+	case RT5659_SPK_EX_LMT_CTRL_7:
+	case RT5659_ADJ_HPF_CTRL_1:
+	case RT5659_ADJ_HPF_CTRL_2:
+	case RT5659_SPK_DC_CAILB_CTRL_1:
+	case RT5659_SPK_DC_CAILB_CTRL_2:
+	case RT5659_SPK_DC_CAILB_CTRL_3:
+	case RT5659_SPK_DC_CAILB_CTRL_4:
+	case RT5659_SPK_DC_CAILB_CTRL_5:
+	case RT5659_SPK_DC_CAILB_STA_1:
+	case RT5659_SPK_DC_CAILB_STA_2:
+	case RT5659_SPK_DC_CAILB_STA_3:
+	case RT5659_SPK_DC_CAILB_STA_4:
+	case RT5659_SPK_DC_CAILB_STA_5:
+	case RT5659_SPK_DC_CAILB_STA_6:
+	case RT5659_SPK_DC_CAILB_STA_7:
+	case RT5659_SPK_DC_CAILB_STA_8:
+	case RT5659_SPK_DC_CAILB_STA_9:
+	case RT5659_SPK_DC_CAILB_STA_10:
+	case RT5659_SPK_VDD_STA_1:
+	case RT5659_SPK_VDD_STA_2:
+	case RT5659_SPK_DC_DET_CTRL_1:
+	case RT5659_SPK_DC_DET_CTRL_2:
+	case RT5659_SPK_DC_DET_CTRL_3:
+	case RT5659_PURE_DC_DET_CTRL_1:
+	case RT5659_PURE_DC_DET_CTRL_2:
+	case RT5659_DUMMY_4:
+	case RT5659_DUMMY_5:
+	case RT5659_DUMMY_6:
+	case RT5659_DRC1_CTRL_1:
+	case RT5659_DRC1_CTRL_2:
+	case RT5659_DRC1_CTRL_3:
+	case RT5659_DRC1_CTRL_4:
+	case RT5659_DRC1_CTRL_5:
+	case RT5659_DRC1_CTRL_6:
+	case RT5659_DRC1_HARD_LMT_CTRL_1:
+	case RT5659_DRC1_HARD_LMT_CTRL_2:
+	case RT5659_DRC2_CTRL_1:
+	case RT5659_DRC2_CTRL_2:
+	case RT5659_DRC2_CTRL_3:
+	case RT5659_DRC2_CTRL_4:
+	case RT5659_DRC2_CTRL_5:
+	case RT5659_DRC2_CTRL_6:
+	case RT5659_DRC2_HARD_LMT_CTRL_1:
+	case RT5659_DRC2_HARD_LMT_CTRL_2:
+	case RT5659_DRC1_PRIV_1:
+	case RT5659_DRC1_PRIV_2:
+	case RT5659_DRC1_PRIV_3:
+	case RT5659_DRC1_PRIV_4:
+	case RT5659_DRC1_PRIV_5:
+	case RT5659_DRC1_PRIV_6:
+	case RT5659_DRC1_PRIV_7:
+	case RT5659_DRC2_PRIV_1:
+	case RT5659_DRC2_PRIV_2:
+	case RT5659_DRC2_PRIV_3:
+	case RT5659_DRC2_PRIV_4:
+	case RT5659_DRC2_PRIV_5:
+	case RT5659_DRC2_PRIV_6:
+	case RT5659_DRC2_PRIV_7:
+	case RT5659_MULTI_DRC_CTRL:
+	case RT5659_CROSS_OVER_1:
+	case RT5659_CROSS_OVER_2:
+	case RT5659_CROSS_OVER_3:
+	case RT5659_CROSS_OVER_4:
+	case RT5659_CROSS_OVER_5:
+	case RT5659_CROSS_OVER_6:
+	case RT5659_CROSS_OVER_7:
+	case RT5659_CROSS_OVER_8:
+	case RT5659_CROSS_OVER_9:
+	case RT5659_CROSS_OVER_10:
+	case RT5659_ALC_PGA_CTRL_1:
+	case RT5659_ALC_PGA_CTRL_2:
+	case RT5659_ALC_PGA_CTRL_3:
+	case RT5659_ALC_PGA_CTRL_4:
+	case RT5659_ALC_PGA_CTRL_5:
+	case RT5659_ALC_PGA_CTRL_6:
+	case RT5659_ALC_PGA_CTRL_7:
+	case RT5659_ALC_PGA_CTRL_8:
+	case RT5659_ALC_PGA_STA_1:
+	case RT5659_ALC_PGA_STA_2:
+	case RT5659_ALC_PGA_STA_3:
+	case RT5659_DAC_L_EQ_PRE_VOL:
+	case RT5659_DAC_R_EQ_PRE_VOL:
+	case RT5659_DAC_L_EQ_POST_VOL:
+	case RT5659_DAC_R_EQ_POST_VOL:
+	case RT5659_DAC_L_EQ_LPF1_A1:
+	case RT5659_DAC_L_EQ_LPF1_H0:
+	case RT5659_DAC_R_EQ_LPF1_A1:
+	case RT5659_DAC_R_EQ_LPF1_H0:
+	case RT5659_DAC_L_EQ_BPF2_A1:
+	case RT5659_DAC_L_EQ_BPF2_A2:
+	case RT5659_DAC_L_EQ_BPF2_H0:
+	case RT5659_DAC_R_EQ_BPF2_A1:
+	case RT5659_DAC_R_EQ_BPF2_A2:
+	case RT5659_DAC_R_EQ_BPF2_H0:
+	case RT5659_DAC_L_EQ_BPF3_A1:
+	case RT5659_DAC_L_EQ_BPF3_A2:
+	case RT5659_DAC_L_EQ_BPF3_H0:
+	case RT5659_DAC_R_EQ_BPF3_A1:
+	case RT5659_DAC_R_EQ_BPF3_A2:
+	case RT5659_DAC_R_EQ_BPF3_H0:
+	case RT5659_DAC_L_EQ_BPF4_A1:
+	case RT5659_DAC_L_EQ_BPF4_A2:
+	case RT5659_DAC_L_EQ_BPF4_H0:
+	case RT5659_DAC_R_EQ_BPF4_A1:
+	case RT5659_DAC_R_EQ_BPF4_A2:
+	case RT5659_DAC_R_EQ_BPF4_H0:
+	case RT5659_DAC_L_EQ_HPF1_A1:
+	case RT5659_DAC_L_EQ_HPF1_H0:
+	case RT5659_DAC_R_EQ_HPF1_A1:
+	case RT5659_DAC_R_EQ_HPF1_H0:
+	case RT5659_DAC_L_EQ_HPF2_A1:
+	case RT5659_DAC_L_EQ_HPF2_A2:
+	case RT5659_DAC_L_EQ_HPF2_H0:
+	case RT5659_DAC_R_EQ_HPF2_A1:
+	case RT5659_DAC_R_EQ_HPF2_A2:
+	case RT5659_DAC_R_EQ_HPF2_H0:
+	case RT5659_DAC_L_BI_EQ_BPF1_H0_1:
+	case RT5659_DAC_L_BI_EQ_BPF1_H0_2:
+	case RT5659_DAC_L_BI_EQ_BPF1_B1_1:
+	case RT5659_DAC_L_BI_EQ_BPF1_B1_2:
+	case RT5659_DAC_L_BI_EQ_BPF1_B2_1:
+	case RT5659_DAC_L_BI_EQ_BPF1_B2_2:
+	case RT5659_DAC_L_BI_EQ_BPF1_A1_1:
+	case RT5659_DAC_L_BI_EQ_BPF1_A1_2:
+	case RT5659_DAC_L_BI_EQ_BPF1_A2_1:
+	case RT5659_DAC_L_BI_EQ_BPF1_A2_2:
+	case RT5659_DAC_R_BI_EQ_BPF1_H0_1:
+	case RT5659_DAC_R_BI_EQ_BPF1_H0_2:
+	case RT5659_DAC_R_BI_EQ_BPF1_B1_1:
+	case RT5659_DAC_R_BI_EQ_BPF1_B1_2:
+	case RT5659_DAC_R_BI_EQ_BPF1_B2_1:
+	case RT5659_DAC_R_BI_EQ_BPF1_B2_2:
+	case RT5659_DAC_R_BI_EQ_BPF1_A1_1:
+	case RT5659_DAC_R_BI_EQ_BPF1_A1_2:
+	case RT5659_DAC_R_BI_EQ_BPF1_A2_1:
+	case RT5659_DAC_R_BI_EQ_BPF1_A2_2:
+	case RT5659_ADC_L_EQ_LPF1_A1:
+	case RT5659_ADC_R_EQ_LPF1_A1:
+	case RT5659_ADC_L_EQ_LPF1_H0:
+	case RT5659_ADC_R_EQ_LPF1_H0:
+	case RT5659_ADC_L_EQ_BPF1_A1:
+	case RT5659_ADC_R_EQ_BPF1_A1:
+	case RT5659_ADC_L_EQ_BPF1_A2:
+	case RT5659_ADC_R_EQ_BPF1_A2:
+	case RT5659_ADC_L_EQ_BPF1_H0:
+	case RT5659_ADC_R_EQ_BPF1_H0:
+	case RT5659_ADC_L_EQ_BPF2_A1:
+	case RT5659_ADC_R_EQ_BPF2_A1:
+	case RT5659_ADC_L_EQ_BPF2_A2:
+	case RT5659_ADC_R_EQ_BPF2_A2:
+	case RT5659_ADC_L_EQ_BPF2_H0:
+	case RT5659_ADC_R_EQ_BPF2_H0:
+	case RT5659_ADC_L_EQ_BPF3_A1:
+	case RT5659_ADC_R_EQ_BPF3_A1:
+	case RT5659_ADC_L_EQ_BPF3_A2:
+	case RT5659_ADC_R_EQ_BPF3_A2:
+	case RT5659_ADC_L_EQ_BPF3_H0:
+	case RT5659_ADC_R_EQ_BPF3_H0:
+	case RT5659_ADC_L_EQ_BPF4_A1:
+	case RT5659_ADC_R_EQ_BPF4_A1:
+	case RT5659_ADC_L_EQ_BPF4_A2:
+	case RT5659_ADC_R_EQ_BPF4_A2:
+	case RT5659_ADC_L_EQ_BPF4_H0:
+	case RT5659_ADC_R_EQ_BPF4_H0:
+	case RT5659_ADC_L_EQ_HPF1_A1:
+	case RT5659_ADC_R_EQ_HPF1_A1:
+	case RT5659_ADC_L_EQ_HPF1_H0:
+	case RT5659_ADC_R_EQ_HPF1_H0:
+	case RT5659_ADC_L_EQ_PRE_VOL:
+	case RT5659_ADC_R_EQ_PRE_VOL:
+	case RT5659_ADC_L_EQ_POST_VOL:
+	case RT5659_ADC_R_EQ_POST_VOL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+static const DECLARE_TLV_DB_SCALE(in_bst_tlv, -1200, 75, 0);
+
+/* Interface data select */
+static const char * const rt5659_data_select[] = {
+	"L/R", "R/L", "L/L", "R/R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if1_01_adc_enum,
+	RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT01_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if1_23_adc_enum,
+	RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT23_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if1_45_adc_enum,
+	RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT45_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if1_67_adc_enum,
+	RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT67_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if2_dac_enum,
+	RT5659_DIG_INF23_DATA, RT5659_IF2_DAC_SEL_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if2_adc_enum,
+	RT5659_DIG_INF23_DATA, RT5659_IF2_ADC_SEL_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if3_dac_enum,
+	RT5659_DIG_INF23_DATA, RT5659_IF3_DAC_SEL_SFT, rt5659_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5659_if3_adc_enum,
+	RT5659_DIG_INF23_DATA, RT5659_IF3_ADC_SEL_SFT, rt5659_data_select);
+
+static const struct snd_kcontrol_new rt5659_if1_01_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 01 ADC Swap Source", rt5659_if1_01_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if1_23_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 23 ADC1 Swap Source", rt5659_if1_23_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if1_45_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 45 ADC1 Swap Source", rt5659_if1_45_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if1_67_adc_swap_mux =
+	SOC_DAPM_ENUM("IF1 67 ADC1 Swap Source", rt5659_if1_67_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if2_dac_swap_mux =
+	SOC_DAPM_ENUM("IF2 DAC Swap Source", rt5659_if2_dac_enum);
+
+static const struct snd_kcontrol_new rt5659_if2_adc_swap_mux =
+	SOC_DAPM_ENUM("IF2 ADC Swap Source", rt5659_if2_adc_enum);
+
+static const struct snd_kcontrol_new rt5659_if3_dac_swap_mux =
+	SOC_DAPM_ENUM("IF3 DAC Swap Source", rt5659_if3_dac_enum);
+
+static const struct snd_kcontrol_new rt5659_if3_adc_swap_mux =
+	SOC_DAPM_ENUM("IF3 ADC Swap Source", rt5659_if3_adc_enum);
+
+static const char * const rt5659_asrc_clk_src[] = {
+	"clk_sysy_div_out", "clk_i2s1_track", "clk_i2s2_track",
+	"clk_i2s3_track", "clk_sys2", "clk_sys3"
+};
+
+static unsigned int rt5659_asrc_clk_map_values[] = {
+	0, 1, 2, 3, 5, 6,
+};
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+	rt5659_da_sto_asrc_enum, RT5659_ASRC_2, RT5659_DA_STO_T_SFT, 0x7,
+	rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+	rt5659_da_monol_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_L_T_SFT, 0x7,
+	rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+	rt5659_da_monor_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_R_T_SFT, 0x7,
+	rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+	rt5659_ad_sto1_asrc_enum, RT5659_ASRC_2, RT5659_AD_STO1_T_SFT, 0x7,
+	rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+	rt5659_ad_sto2_asrc_enum, RT5659_ASRC_3, RT5659_AD_STO2_T_SFT, 0x7,
+	rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+	rt5659_ad_monol_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_L_T_SFT, 0x7,
+	rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+	rt5659_ad_monor_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_R_T_SFT, 0x7,
+	rt5659_asrc_clk_src, rt5659_asrc_clk_map_values);
+
+static int rt5659_hp_vol_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+	int ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+	if (snd_soc_read(codec, RT5659_STO_NG2_CTRL_1) & RT5659_NG2_EN) {
+		snd_soc_update_bits(codec, RT5659_STO_NG2_CTRL_1,
+			RT5659_NG2_EN_MASK, RT5659_NG2_DIS);
+		snd_soc_update_bits(codec, RT5659_STO_NG2_CTRL_1,
+			RT5659_NG2_EN_MASK, RT5659_NG2_EN);
+	}
+
+	return ret;
+}
+
+static void rt5659_enable_push_button_irq(struct snd_soc_codec *codec,
+	bool enable)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+	if (enable) {
+		snd_soc_write(codec, RT5659_4BTN_IL_CMD_1, 0x000b);
+
+		/* MICBIAS1 and Mic Det Power for button detect*/
+		snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+		snd_soc_dapm_force_enable_pin(dapm,
+			"Mic Det Power");
+		snd_soc_dapm_sync(dapm);
+
+		snd_soc_update_bits(codec, RT5659_PWR_ANLG_2,
+			RT5659_PWR_MB1, RT5659_PWR_MB1);
+		snd_soc_update_bits(codec, RT5659_PWR_VOL,
+			RT5659_PWR_MIC_DET, RT5659_PWR_MIC_DET);
+
+		snd_soc_update_bits(codec, RT5659_IRQ_CTRL_2,
+				RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_EN);
+		snd_soc_update_bits(codec, RT5659_4BTN_IL_CMD_2,
+				RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_EN);
+	} else {
+		snd_soc_update_bits(codec, RT5659_4BTN_IL_CMD_2,
+				RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_DIS);
+		snd_soc_update_bits(codec, RT5659_IRQ_CTRL_2,
+				RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_DIS);
+		/* MICBIAS1 and Mic Det Power for button detect*/
+		snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+		snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+		snd_soc_dapm_sync(dapm);
+	}
+}
+
+/**
+ * rt5659_headset_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 rt5659_headset_detect(struct snd_soc_codec *codec, int jack_insert)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+	int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30};
+	int reg_63;
+
+	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+	if (jack_insert) {
+		snd_soc_dapm_force_enable_pin(dapm,
+			"Mic Det Power");
+		snd_soc_dapm_sync(dapm);
+		reg_63 = snd_soc_read(codec, RT5659_PWR_ANLG_1);
+
+		snd_soc_update_bits(codec, RT5659_PWR_ANLG_1,
+			RT5659_PWR_VREF2 | RT5659_PWR_MB,
+			RT5659_PWR_VREF2 | RT5659_PWR_MB);
+		msleep(20);
+		snd_soc_update_bits(codec, RT5659_PWR_ANLG_1,
+			RT5659_PWR_FV2, RT5659_PWR_FV2);
+
+		snd_soc_write(codec, RT5659_EJD_CTRL_2, 0x4160);
+		snd_soc_update_bits(codec, RT5659_EJD_CTRL_1,
+			0x20, 0x0);
+		msleep(20);
+		snd_soc_update_bits(codec, RT5659_EJD_CTRL_1,
+			0x20, 0x20);
+
+		while (i < 5) {
+			msleep(sleep_time[i]);
+			val = snd_soc_read(codec, RT5659_EJD_CTRL_2) & 0x0003;
+			i++;
+			if (val == 0x1 || val == 0x2 || val == 0x3)
+				break;
+		}
+
+		switch (val) {
+		case 1:
+			rt5659->jack_type = SND_JACK_HEADSET;
+			rt5659_enable_push_button_irq(codec, true);
+			break;
+		default:
+			snd_soc_write(codec, RT5659_PWR_ANLG_1, reg_63);
+			rt5659->jack_type = SND_JACK_HEADPHONE;
+			snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+			snd_soc_dapm_sync(dapm);
+			break;
+		}
+	} else {
+		snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
+		snd_soc_dapm_sync(dapm);
+		if (rt5659->jack_type == SND_JACK_HEADSET)
+			rt5659_enable_push_button_irq(codec, false);
+		rt5659->jack_type = 0;
+	}
+
+	dev_dbg(codec->dev, "jack_type = %d\n", rt5659->jack_type);
+	return rt5659->jack_type;
+}
+
+static int rt5659_button_detect(struct snd_soc_codec *codec)
+{
+	int btn_type, val;
+
+	val = snd_soc_read(codec, RT5659_4BTN_IL_CMD_1);
+	btn_type = val & 0xfff0;
+	snd_soc_write(codec, RT5659_4BTN_IL_CMD_1, val);
+
+	return btn_type;
+}
+
+static irqreturn_t rt5659_irq(int irq, void *data)
+{
+	struct rt5659_priv *rt5659 = data;
+
+	queue_delayed_work(system_power_efficient_wq,
+			   &rt5659->jack_detect_work, msecs_to_jiffies(250));
+
+	return IRQ_HANDLED;
+}
+
+int rt5659_set_jack_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *hs_jack)
+{
+	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+	rt5659->hs_jack = hs_jack;
+
+	rt5659_irq(0, rt5659);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5659_set_jack_detect);
+
+static void rt5659_jack_detect_work(struct work_struct *work)
+{
+	struct rt5659_priv *rt5659 =
+		container_of(work, struct rt5659_priv, jack_detect_work.work);
+	int val, btn_type, report = 0;
+
+	if (!rt5659->codec)
+		return;
+
+	val = snd_soc_read(rt5659->codec, RT5659_INT_ST_1) & 0x0080;
+	if (!val) {
+		/* jack in */
+		if (rt5659->jack_type == 0) {
+			/* jack was out, report jack type */
+			report = rt5659_headset_detect(rt5659->codec, 1);
+		} else {
+			/* jack is already in, report button event */
+			report = SND_JACK_HEADSET;
+			btn_type = rt5659_button_detect(rt5659->codec);
+			/**
+			 * rt5659 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(rt5659->codec->dev,
+					"Unexpected button code 0x%04x\n",
+					btn_type);
+				break;
+			}
+
+			/* button release or spurious interrput*/
+			if (btn_type == 0)
+				report =  rt5659->jack_type;
+		}
+	} else {
+		/* jack out */
+		report = rt5659_headset_detect(rt5659->codec, 0);
+	}
+
+	snd_soc_jack_report(rt5659->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 rt5659_snd_controls[] = {
+	/* Speaker Output Volume */
+	SOC_DOUBLE_TLV("Speaker Playback Volume", RT5659_SPO_VOL,
+		RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+	/* Headphone Output Volume */
+	SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", RT5659_HPL_GAIN,
+		RT5659_HPR_GAIN, RT5659_G_HP_SFT, 31, 1, snd_soc_get_volsw,
+		rt5659_hp_vol_put, hp_vol_tlv),
+
+	/* Mono Output Volume */
+	SOC_SINGLE_TLV("Mono Playback Volume", RT5659_MONO_OUT,
+		RT5659_L_VOL_SFT, 39, 1, out_vol_tlv),
+
+	/* Output Volume */
+	SOC_DOUBLE_TLV("OUT Playback Volume", RT5659_LOUT,
+		RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+	/* DAC Digital Volume */
+	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5659_DAC1_DIG_VOL,
+		RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 175, 0, dac_vol_tlv),
+	SOC_DOUBLE("DAC1 Playback Switch", RT5659_AD_DA_MIXER,
+		RT5659_M_DAC1_L_SFT, RT5659_M_DAC1_R_SFT, 1, 1),
+
+	SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5659_DAC2_DIG_VOL,
+		RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 175, 0, dac_vol_tlv),
+	SOC_DOUBLE("DAC2 Playback Switch", RT5659_DAC_CTRL,
+		RT5659_M_DAC2_L_VOL_SFT, RT5659_M_DAC2_R_VOL_SFT, 1, 1),
+
+	/* IN1/IN2/IN3/IN4 Volume */
+	SOC_SINGLE_TLV("IN1 Boost Volume", RT5659_IN1_IN2,
+		RT5659_BST1_SFT, 69, 0, in_bst_tlv),
+	SOC_SINGLE_TLV("IN2 Boost Volume", RT5659_IN1_IN2,
+		RT5659_BST2_SFT, 69, 0, in_bst_tlv),
+	SOC_SINGLE_TLV("IN3 Boost Volume", RT5659_IN3_IN4,
+		RT5659_BST3_SFT, 69, 0, in_bst_tlv),
+	SOC_SINGLE_TLV("IN4 Boost Volume", RT5659_IN3_IN4,
+		RT5659_BST4_SFT, 69, 0, in_bst_tlv),
+
+	/* INL/INR Volume Control */
+	SOC_DOUBLE_TLV("IN Capture Volume", RT5659_INL1_INR1_VOL,
+		RT5659_INL_VOL_SFT, RT5659_INR_VOL_SFT, 31, 1, in_vol_tlv),
+
+	/* ADC Digital Volume Control */
+	SOC_DOUBLE("STO1 ADC Capture Switch", RT5659_STO1_ADC_DIG_VOL,
+		RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5659_STO1_ADC_DIG_VOL,
+		RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv),
+	SOC_DOUBLE("Mono ADC Capture Switch", RT5659_MONO_ADC_DIG_VOL,
+		RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5659_MONO_ADC_DIG_VOL,
+		RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv),
+	SOC_DOUBLE("STO2 ADC Capture Switch", RT5659_STO2_ADC_DIG_VOL,
+		RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1),
+	SOC_DOUBLE_TLV("STO2 ADC Capture Volume", RT5659_STO2_ADC_DIG_VOL,
+		RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv),
+
+	/* ADC Boost Volume Control */
+	SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5659_STO1_BOOST,
+		RT5659_STO1_ADC_L_BST_SFT, RT5659_STO1_ADC_R_BST_SFT,
+		3, 0, adc_bst_tlv),
+
+	SOC_DOUBLE_TLV("Mono ADC Boost Gain Volume", RT5659_MONO_BOOST,
+		RT5659_MONO_ADC_L_BST_SFT, RT5659_MONO_ADC_R_BST_SFT,
+		3, 0, adc_bst_tlv),
+
+	SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5659_STO2_BOOST,
+		RT5659_STO2_ADC_L_BST_SFT, RT5659_STO2_ADC_R_BST_SFT,
+		3, 0, adc_bst_tlv),
+
+	SOC_SINGLE("DAC IF1 DAC1 L Data Switch", RT5659_TDM_CTRL_4, 12, 7, 0),
+	SOC_SINGLE("DAC IF1 DAC1 R Data Switch", RT5659_TDM_CTRL_4, 8, 7, 0),
+	SOC_SINGLE("DAC IF1 DAC2 L Data Switch", RT5659_TDM_CTRL_4, 4, 7, 0),
+	SOC_SINGLE("DAC IF1 DAC2 R Data Switch", RT5659_TDM_CTRL_4, 0, 7, 0),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int 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 rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	int pd, idx = -EINVAL;
+
+	pd = rl6231_get_pre_div(rt5659->regmap,
+		RT5659_ADDA_CLK_1, RT5659_I2S_PD1_SFT);
+	idx = rl6231_calc_dmic_clk(rt5659->sysclk / pd);
+
+	if (idx < 0)
+		dev_err(codec->dev, "Failed to set DMIC clock\n");
+	else {
+		snd_soc_update_bits(codec, RT5659_DMIC_CTRL_1,
+			RT5659_DMIC_CLK_MASK, idx << RT5659_DMIC_CLK_SFT);
+	}
+	return idx;
+}
+
+static int set_adc_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);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, RT5659_CHOP_ADC,
+			RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK,
+			RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, RT5659_CHOP_ADC,
+			RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK, 0);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+
+}
+
+static int rt5659_charge_pump_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_PRE_PMU:
+		/* Depop */
+		snd_soc_write(codec, RT5659_DEPOP_1, 0x0009);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_write(codec, RT5659_HP_CHARGE_PUMP_1, 0x0c16);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int 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, RT5659_GLB_CLK);
+	val &= RT5659_SCLK_SRC_MASK;
+	if (val == RT5659_SCLK_SRC_PLL1)
+		return 1;
+	else
+		return 0;
+}
+
+static int 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);
+
+	switch (w->shift) {
+	case RT5659_ADC_MONO_R_ASRC_SFT:
+		reg = RT5659_ASRC_3;
+		shift = RT5659_AD_MONO_R_T_SFT;
+		break;
+	case RT5659_ADC_MONO_L_ASRC_SFT:
+		reg = RT5659_ASRC_3;
+		shift = RT5659_AD_MONO_L_T_SFT;
+		break;
+	case RT5659_ADC_STO1_ASRC_SFT:
+		reg = RT5659_ASRC_2;
+		shift = RT5659_AD_STO1_T_SFT;
+		break;
+	case RT5659_DAC_MONO_R_ASRC_SFT:
+		reg = RT5659_ASRC_2;
+		shift = RT5659_DA_MONO_R_T_SFT;
+		break;
+	case RT5659_DAC_MONO_L_ASRC_SFT:
+		reg = RT5659_ASRC_2;
+		shift = RT5659_DA_MONO_L_T_SFT;
+		break;
+	case RT5659_DAC_STO_ASRC_SFT:
+		reg = RT5659_ASRC_2;
+		shift = RT5659_DA_STO_T_SFT;
+		break;
+	default:
+		return 0;
+	}
+
+	val = (snd_soc_read(codec, reg) >> shift) & 0xf;
+	switch (val) {
+	case 1:
+	case 2:
+	case 3:
+		/* I2S_Pre_Div1 should be 1 in asrc mode */
+		snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+			RT5659_I2S_PD1_MASK, RT5659_I2S_PD1_2);
+		return 1;
+	default:
+		return 0;
+	}
+
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5659_sto1_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5659_STO1_ADC_MIXER,
+			RT5659_M_STO1_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5659_STO1_ADC_MIXER,
+			RT5659_M_STO1_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_sto1_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5659_STO1_ADC_MIXER,
+			RT5659_M_STO1_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5659_STO1_ADC_MIXER,
+			RT5659_M_STO1_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5659_MONO_ADC_MIXER,
+			RT5659_M_MONO_ADC_L1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5659_MONO_ADC_MIXER,
+			RT5659_M_MONO_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r_mix[] = {
+	SOC_DAPM_SINGLE("ADC1 Switch", RT5659_MONO_ADC_MIXER,
+			RT5659_M_MONO_ADC_R1_SFT, 1, 1),
+	SOC_DAPM_SINGLE("ADC2 Switch", RT5659_MONO_ADC_MIXER,
+			RT5659_M_MONO_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5659_AD_DA_MIXER,
+			RT5659_M_ADCMIX_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5659_AD_DA_MIXER,
+			RT5659_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("Stereo ADC Switch", RT5659_AD_DA_MIXER,
+			RT5659_M_ADCMIX_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC1 Switch", RT5659_AD_DA_MIXER,
+			RT5659_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_sto_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_L1_STO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_R1_STO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_L2_STO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_R2_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_sto_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_L1_STO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_R1_STO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_L2_STO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_STO_DAC_MIXER,
+			RT5659_M_DAC_R2_STO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_dac_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_L1_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_R1_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_L2_MONO_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_R2_MONO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_dac_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_L1_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_R1_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_L2_MONO_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONO_DAC_MIXER,
+			RT5659_M_DAC_R2_MONO_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5659_rec1_l_mix[] = {
+	SOC_DAPM_SINGLE("SPKVOLL Switch", RT5659_REC1_L2_MIXER,
+			RT5659_M_SPKVOLL_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5659_REC1_L2_MIXER,
+			RT5659_M_INL_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC1_L2_MIXER,
+			RT5659_M_BST4_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC1_L2_MIXER,
+			RT5659_M_BST3_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC1_L2_MIXER,
+			RT5659_M_BST2_RM1_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC1_L2_MIXER,
+			RT5659_M_BST1_RM1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_rec1_r_mix[] = {
+	SOC_DAPM_SINGLE("HPOVOLR Switch", RT5659_REC1_L2_MIXER,
+			RT5659_M_HPOVOLR_RM1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5659_REC1_R2_MIXER,
+			RT5659_M_INR_RM1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC1_R2_MIXER,
+			RT5659_M_BST4_RM1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC1_R2_MIXER,
+			RT5659_M_BST3_RM1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC1_R2_MIXER,
+			RT5659_M_BST2_RM1_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC1_R2_MIXER,
+			RT5659_M_BST1_RM1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_rec2_l_mix[] = {
+	SOC_DAPM_SINGLE("SPKVOLL Switch", RT5659_REC2_L2_MIXER,
+			RT5659_M_SPKVOL_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOLL Switch", RT5659_REC2_L2_MIXER,
+			RT5659_M_OUTVOLL_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC2_L2_MIXER,
+			RT5659_M_BST4_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC2_L2_MIXER,
+			RT5659_M_BST3_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC2_L2_MIXER,
+			RT5659_M_BST2_RM2_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC2_L2_MIXER,
+			RT5659_M_BST1_RM2_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_rec2_r_mix[] = {
+	SOC_DAPM_SINGLE("MONOVOL Switch", RT5659_REC2_R2_MIXER,
+			RT5659_M_MONOVOL_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOLR Switch", RT5659_REC2_R2_MIXER,
+			RT5659_M_OUTVOLR_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC2_R2_MIXER,
+			RT5659_M_BST4_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC2_R2_MIXER,
+			RT5659_M_BST3_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC2_R2_MIXER,
+			RT5659_M_BST2_RM2_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC2_R2_MIXER,
+			RT5659_M_BST1_RM2_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_spk_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_SPK_L_MIXER,
+			RT5659_M_DAC_L2_SM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5659_SPK_L_MIXER,
+			RT5659_M_BST1_SM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5659_SPK_L_MIXER,
+			RT5659_M_IN_L_SM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5659_SPK_L_MIXER,
+			RT5659_M_IN_R_SM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_SPK_L_MIXER,
+			RT5659_M_BST3_SM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_spk_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_SPK_R_MIXER,
+			RT5659_M_DAC_R2_SM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5659_SPK_R_MIXER,
+			RT5659_M_BST4_SM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5659_SPK_R_MIXER,
+			RT5659_M_IN_L_SM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5659_SPK_R_MIXER,
+			RT5659_M_IN_R_SM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_SPK_R_MIXER,
+			RT5659_M_BST3_SM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_monovol_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONOMIX_IN_GAIN,
+			RT5659_M_DAC_L2_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONOMIX_IN_GAIN,
+			RT5659_M_DAC_R2_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5659_MONOMIX_IN_GAIN,
+			RT5659_M_BST1_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5659_MONOMIX_IN_GAIN,
+			RT5659_M_BST2_MM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_MONOMIX_IN_GAIN,
+			RT5659_M_BST3_MM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_out_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_OUT_L_MIXER,
+			RT5659_M_DAC_L2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INL Switch", RT5659_OUT_L_MIXER,
+			RT5659_M_IN_L_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST1 Switch", RT5659_OUT_L_MIXER,
+			RT5659_M_BST1_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5659_OUT_L_MIXER,
+			RT5659_M_BST2_OM_L_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_OUT_L_MIXER,
+			RT5659_M_BST3_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_out_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_OUT_R_MIXER,
+			RT5659_M_DAC_R2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("INR Switch", RT5659_OUT_R_MIXER,
+			RT5659_M_IN_R_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST2 Switch", RT5659_OUT_R_MIXER,
+			RT5659_M_BST2_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST3 Switch", RT5659_OUT_R_MIXER,
+			RT5659_M_BST3_OM_R_SFT, 1, 1),
+	SOC_DAPM_SINGLE("BST4 Switch", RT5659_OUT_R_MIXER,
+			RT5659_M_BST4_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_spo_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_SPO_AMP_GAIN,
+			RT5659_M_DAC_L2_SPKOMIX_SFT, 1, 0),
+	SOC_DAPM_SINGLE("SPKVOL L Switch", RT5659_SPO_AMP_GAIN,
+			RT5659_M_SPKVOLL_SPKOMIX_SFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rt5659_spo_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_SPO_AMP_GAIN,
+			RT5659_M_DAC_R2_SPKOMIX_SFT, 1, 0),
+	SOC_DAPM_SINGLE("SPKVOL R Switch", RT5659_SPO_AMP_GAIN,
+			RT5659_M_SPKVOLR_SPKOMIX_SFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rt5659_mono_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONOMIX_IN_GAIN,
+			RT5659_M_DAC_L2_MA_SFT, 1, 1),
+	SOC_DAPM_SINGLE("MONOVOL Switch", RT5659_MONOMIX_IN_GAIN,
+			RT5659_M_MONOVOL_MA_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_lout_l_mix[] = {
+	SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_LOUT_MIXER,
+			RT5659_M_DAC_L2_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL L Switch", RT5659_LOUT_MIXER,
+			RT5659_M_OV_L_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5659_lout_r_mix[] = {
+	SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_LOUT_MIXER,
+			RT5659_M_DAC_R2_LM_SFT, 1, 1),
+	SOC_DAPM_SINGLE("OUTVOL R Switch", RT5659_LOUT_MIXER,
+			RT5659_M_OV_R_LM_SFT, 1, 1),
+};
+
+/*DAC L2, DAC R2*/
+/*MX-1B [6:4], MX-1B [2:0]*/
+static const char * const rt5659_dac2_src[] = {
+	"IF1 DAC2", "IF2 DAC", "IF3 DAC", "Mono ADC MIX"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_dac_l2_enum, RT5659_DAC_CTRL,
+	RT5659_DAC_L2_SEL_SFT, rt5659_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_dac_l2_mux =
+	SOC_DAPM_ENUM("DAC L2 Source", rt5659_dac_l2_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_dac_r2_enum, RT5659_DAC_CTRL,
+	RT5659_DAC_R2_SEL_SFT, rt5659_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_dac_r2_mux =
+	SOC_DAPM_ENUM("DAC R2 Source", rt5659_dac_r2_enum);
+
+
+/* STO1 ADC1 Source */
+/* MX-26 [13] */
+static const char * const rt5659_sto1_adc1_src[] = {
+	"DAC MIX", "ADC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_sto1_adc1_enum, RT5659_STO1_ADC_MIXER,
+	RT5659_STO1_ADC1_SRC_SFT, rt5659_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_adc1_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC1 Source", rt5659_sto1_adc1_enum);
+
+/* STO1 ADC Source */
+/* MX-26 [12] */
+static const char * const rt5659_sto1_adc_src[] = {
+	"ADC1", "ADC2"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_sto1_adc_enum, RT5659_STO1_ADC_MIXER,
+	RT5659_STO1_ADC_SRC_SFT, rt5659_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_adc_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC Source", rt5659_sto1_adc_enum);
+
+/* STO1 ADC2 Source */
+/* MX-26 [11] */
+static const char * const rt5659_sto1_adc2_src[] = {
+	"DAC MIX", "DMIC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_sto1_adc2_enum, RT5659_STO1_ADC_MIXER,
+	RT5659_STO1_ADC2_SRC_SFT, rt5659_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_adc2_mux =
+	SOC_DAPM_ENUM("Stereo1 ADC2 Source", rt5659_sto1_adc2_enum);
+
+/* STO1 DMIC Source */
+/* MX-26 [8] */
+static const char * const rt5659_sto1_dmic_src[] = {
+	"DMIC1", "DMIC2"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_sto1_dmic_enum, RT5659_STO1_ADC_MIXER,
+	RT5659_STO1_DMIC_SRC_SFT, rt5659_sto1_dmic_src);
+
+static const struct snd_kcontrol_new rt5659_sto1_dmic_mux =
+	SOC_DAPM_ENUM("Stereo1 DMIC Source", rt5659_sto1_dmic_enum);
+
+
+/* MONO ADC L2 Source */
+/* MX-27 [12] */
+static const char * const rt5659_mono_adc_l2_src[] = {
+	"Mono DAC MIXL", "DMIC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_adc_l2_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_ADC_L2_SRC_SFT, rt5659_mono_adc_l2_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l2_mux =
+	SOC_DAPM_ENUM("Mono ADC L2 Source", rt5659_mono_adc_l2_enum);
+
+
+/* MONO ADC L1 Source */
+/* MX-27 [11] */
+static const char * const rt5659_mono_adc_l1_src[] = {
+	"Mono DAC MIXL", "ADC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_adc_l1_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_ADC_L1_SRC_SFT, rt5659_mono_adc_l1_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l1_mux =
+	SOC_DAPM_ENUM("Mono ADC L1 Source", rt5659_mono_adc_l1_enum);
+
+/* MONO ADC L Source, MONO ADC R Source*/
+/* MX-27 [10:9], MX-27 [2:1] */
+static const char * const rt5659_mono_adc_src[] = {
+	"ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_adc_l_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_ADC_L_SRC_SFT, rt5659_mono_adc_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_l_mux =
+	SOC_DAPM_ENUM("Mono ADC L Source", rt5659_mono_adc_l_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_adcr_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_ADC_R_SRC_SFT, rt5659_mono_adc_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r_mux =
+	SOC_DAPM_ENUM("Mono ADC R Source", rt5659_mono_adcr_enum);
+
+/* MONO DMIC L Source */
+/* MX-27 [8] */
+static const char * const rt5659_mono_dmic_l_src[] = {
+	"DMIC1 L", "DMIC2 L"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_dmic_l_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_DMIC_L_SRC_SFT, rt5659_mono_dmic_l_src);
+
+static const struct snd_kcontrol_new rt5659_mono_dmic_l_mux =
+	SOC_DAPM_ENUM("Mono DMIC L Source", rt5659_mono_dmic_l_enum);
+
+/* MONO ADC R2 Source */
+/* MX-27 [4] */
+static const char * const rt5659_mono_adc_r2_src[] = {
+	"Mono DAC MIXR", "DMIC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_adc_r2_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_ADC_R2_SRC_SFT, rt5659_mono_adc_r2_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r2_mux =
+	SOC_DAPM_ENUM("Mono ADC R2 Source", rt5659_mono_adc_r2_enum);
+
+/* MONO ADC R1 Source */
+/* MX-27 [3] */
+static const char * const rt5659_mono_adc_r1_src[] = {
+	"Mono DAC MIXR", "ADC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_adc_r1_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_ADC_R1_SRC_SFT, rt5659_mono_adc_r1_src);
+
+static const struct snd_kcontrol_new rt5659_mono_adc_r1_mux =
+	SOC_DAPM_ENUM("Mono ADC R1 Source", rt5659_mono_adc_r1_enum);
+
+/* MONO DMIC R Source */
+/* MX-27 [0] */
+static const char * const rt5659_mono_dmic_r_src[] = {
+	"DMIC1 R", "DMIC2 R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_mono_dmic_r_enum, RT5659_MONO_ADC_MIXER,
+	RT5659_MONO_DMIC_R_SRC_SFT, rt5659_mono_dmic_r_src);
+
+static const struct snd_kcontrol_new rt5659_mono_dmic_r_mux =
+	SOC_DAPM_ENUM("Mono DMIC R Source", rt5659_mono_dmic_r_enum);
+
+
+/* DAC R1 Source, DAC L1 Source*/
+/* MX-29 [11:10], MX-29 [9:8]*/
+static const char * const rt5659_dac1_src[] = {
+	"IF1 DAC1", "IF2 DAC", "IF3 DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_dac_r1_enum, RT5659_AD_DA_MIXER,
+	RT5659_DAC1_R_SEL_SFT, rt5659_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_dac_r1_mux =
+	SOC_DAPM_ENUM("DAC R1 Source", rt5659_dac_r1_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_dac_l1_enum, RT5659_AD_DA_MIXER,
+	RT5659_DAC1_L_SEL_SFT, rt5659_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_dac_l1_mux =
+	SOC_DAPM_ENUM("DAC L1 Source", rt5659_dac_l1_enum);
+
+/* DAC Digital Mixer L Source, DAC Digital Mixer R Source*/
+/* MX-2C [6], MX-2C [4]*/
+static const char * const rt5659_dig_dac_mix_src[] = {
+	"Stereo DAC Mixer", "Mono DAC Mixer"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_dig_dac_mixl_enum, RT5659_DIG_MIXER,
+	RT5659_DAC_MIX_L_SFT, rt5659_dig_dac_mix_src);
+
+static const struct snd_kcontrol_new rt5659_dig_dac_mixl_mux =
+	SOC_DAPM_ENUM("DAC Digital Mixer L Source", rt5659_dig_dac_mixl_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_dig_dac_mixr_enum, RT5659_DIG_MIXER,
+	RT5659_DAC_MIX_R_SFT, rt5659_dig_dac_mix_src);
+
+static const struct snd_kcontrol_new rt5659_dig_dac_mixr_mux =
+	SOC_DAPM_ENUM("DAC Digital Mixer R Source", rt5659_dig_dac_mixr_enum);
+
+/* Analog DAC L1 Source, Analog DAC R1 Source*/
+/* MX-2D [3], MX-2D [2]*/
+static const char * const rt5659_alg_dac1_src[] = {
+	"DAC", "Stereo DAC Mixer"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_alg_dac_l1_enum, RT5659_A_DAC_MUX,
+	RT5659_A_DACL1_SFT, rt5659_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_l1_mux =
+	SOC_DAPM_ENUM("Analog DACL1 Source", rt5659_alg_dac_l1_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_alg_dac_r1_enum, RT5659_A_DAC_MUX,
+	RT5659_A_DACR1_SFT, rt5659_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_r1_mux =
+	SOC_DAPM_ENUM("Analog DACR1 Source", rt5659_alg_dac_r1_enum);
+
+/* Analog DAC LR Source, Analog DAC R2 Source*/
+/* MX-2D [1], MX-2D [0]*/
+static const char * const rt5659_alg_dac2_src[] = {
+	"Stereo DAC Mixer", "Mono DAC Mixer"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_alg_dac_l2_enum, RT5659_A_DAC_MUX,
+	RT5659_A_DACL2_SFT, rt5659_alg_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_l2_mux =
+	SOC_DAPM_ENUM("Analog DAC L2 Source", rt5659_alg_dac_l2_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_alg_dac_r2_enum, RT5659_A_DAC_MUX,
+	RT5659_A_DACR2_SFT, rt5659_alg_dac2_src);
+
+static const struct snd_kcontrol_new rt5659_alg_dac_r2_mux =
+	SOC_DAPM_ENUM("Analog DAC R2 Source", rt5659_alg_dac_r2_enum);
+
+/* Interface2 ADC Data Input*/
+/* MX-2F [13:12] */
+static const char * const rt5659_if2_adc_in_src[] = {
+	"IF_ADC1", "IF_ADC2", "DAC_REF", "IF_ADC3"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_if2_adc_in_enum, RT5659_DIG_INF23_DATA,
+	RT5659_IF2_ADC_IN_SFT, rt5659_if2_adc_in_src);
+
+static const struct snd_kcontrol_new rt5659_if2_adc_in_mux =
+	SOC_DAPM_ENUM("IF2 ADC IN Source", rt5659_if2_adc_in_enum);
+
+/* Interface3 ADC Data Input*/
+/* MX-2F [1:0] */
+static const char * const rt5659_if3_adc_in_src[] = {
+	"IF_ADC1", "IF_ADC2", "DAC_REF", "Stereo2_ADC_L/R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_if3_adc_in_enum, RT5659_DIG_INF23_DATA,
+	RT5659_IF3_ADC_IN_SFT, rt5659_if3_adc_in_src);
+
+static const struct snd_kcontrol_new rt5659_if3_adc_in_mux =
+	SOC_DAPM_ENUM("IF3 ADC IN Source", rt5659_if3_adc_in_enum);
+
+/* PDM 1 L/R*/
+/* MX-31 [15] [13] */
+static const char * const rt5659_pdm_src[] = {
+	"Mono DAC", "Stereo DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_pdm_l_enum, RT5659_PDM_OUT_CTRL,
+	RT5659_PDM1_L_SFT, rt5659_pdm_src);
+
+static const struct snd_kcontrol_new rt5659_pdm_l_mux =
+	SOC_DAPM_ENUM("PDM L Source", rt5659_pdm_l_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_pdm_r_enum, RT5659_PDM_OUT_CTRL,
+	RT5659_PDM1_R_SFT, rt5659_pdm_src);
+
+static const struct snd_kcontrol_new rt5659_pdm_r_mux =
+	SOC_DAPM_ENUM("PDM R Source", rt5659_pdm_r_enum);
+
+/* SPDIF Output source*/
+/* MX-36 [1:0] */
+static const char * const rt5659_spdif_src[] = {
+	"IF1_DAC1", "IF1_DAC2", "IF2_DAC", "IF3_DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_spdif_enum, RT5659_SPDIF_CTRL,
+	RT5659_SPDIF_SEL_SFT, rt5659_spdif_src);
+
+static const struct snd_kcontrol_new rt5659_spdif_mux =
+	SOC_DAPM_ENUM("SPDIF Source", rt5659_spdif_enum);
+
+/* I2S1 TDM ADCDAT Source */
+/* MX-78[4:0] */
+static const char * const rt5659_rx_adc_data_src[] = {
+	"AD1:AD2:DAC:NUL", "AD1:AD2:NUL:DAC", "AD1:DAC:AD2:NUL",
+	"AD1:DAC:NUL:AD2", "AD1:NUL:DAC:AD2", "AD1:NUL:AD2:DAC",
+	"AD2:AD1:DAC:NUL", "AD2:AD1:NUL:DAC", "AD2:DAC:AD1:NUL",
+	"AD2:DAC:NUL:AD1", "AD2:NUL:DAC:AD1", "AD1:NUL:AD1:DAC",
+	"DAC:AD1:AD2:NUL", "DAC:AD1:NUL:AD2", "DAC:AD2:AD1:NUL",
+	"DAC:AD2:NUL:AD1", "DAC:NUL:DAC:AD2", "DAC:NUL:AD2:DAC",
+	"NUL:AD1:AD2:DAC", "NUL:AD1:DAC:AD2", "NUL:AD2:AD1:DAC",
+	"NUL:AD2:DAC:AD1", "NUL:DAC:DAC:AD2", "NUL:DAC:AD2:DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+	rt5659_rx_adc_data_enum, RT5659_TDM_CTRL_2,
+	RT5659_ADCDAT_SRC_SFT, rt5659_rx_adc_data_src);
+
+static const struct snd_kcontrol_new rt5659_rx_adc_dac_mux =
+	SOC_DAPM_ENUM("TDM ADCDAT Source", rt5659_rx_adc_data_enum);
+
+/* Out Volume Switch */
+static const struct snd_kcontrol_new spkvol_l_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_SPO_VOL, RT5659_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new spkvol_r_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_SPO_VOL, RT5659_VOL_R_SFT, 1, 1);
+
+static const struct snd_kcontrol_new monovol_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_MONO_OUT, RT5659_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new outvol_l_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new outvol_r_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_VOL_R_SFT, 1, 1);
+
+/* Out Switch */
+static const struct snd_kcontrol_new spo_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_CLASSD_2, RT5659_M_RF_DIG_SFT, 1, 1);
+
+static const struct snd_kcontrol_new mono_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_MONO_OUT, RT5659_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_l_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_HP_VOL, RT5659_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_r_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_HP_VOL, RT5659_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_l_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_r_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new pdm_l_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_PDM_OUT_CTRL, RT5659_M_PDM1_L_SFT, 1,
+		1);
+
+static const struct snd_kcontrol_new pdm_r_switch =
+	SOC_DAPM_SINGLE("Switch", RT5659_PDM_OUT_CTRL, RT5659_M_PDM1_R_SFT, 1,
+		1);
+
+static int rt5659_spk_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_PRE_PMU:
+		snd_soc_update_bits(codec, RT5659_CLASSD_CTRL_1,
+			RT5659_POW_CLSD_DB_MASK, RT5659_POW_CLSD_DB_EN);
+		snd_soc_update_bits(codec, RT5659_CLASSD_2,
+			RT5659_M_RI_DIG, RT5659_M_RI_DIG);
+		snd_soc_write(codec, RT5659_CLASSD_1, 0x0803);
+		snd_soc_write(codec, RT5659_SPK_DC_CAILB_CTRL_3, 0x0000);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_write(codec, RT5659_CLASSD_1, 0x0011);
+		snd_soc_update_bits(codec, RT5659_CLASSD_2,
+			RT5659_M_RI_DIG, 0x0);
+		snd_soc_write(codec, RT5659_SPK_DC_CAILB_CTRL_3, 0x0003);
+		snd_soc_update_bits(codec, RT5659_CLASSD_CTRL_1,
+			RT5659_POW_CLSD_DB_MASK, RT5659_POW_CLSD_DB_DIS);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+
+}
+
+static int rt5659_mono_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_PRE_PMU:
+		snd_soc_write(codec, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e00);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_write(codec, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e04);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+
+}
+
+static int rt5659_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);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_write(codec, RT5659_HP_CHARGE_PUMP_1, 0x0e1e);
+		snd_soc_update_bits(codec, RT5659_DEPOP_1, 0x0010, 0x0010);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_write(codec, RT5659_DEPOP_1, 0x0000);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int set_dmic_power(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/*Add delay to avoid pop noise*/
+		msleep(450);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5659_dapm_widgets[] = {
+	SND_SOC_DAPM_SUPPLY("LDO2", RT5659_PWR_ANLG_3, RT5659_PWR_LDO2_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("PLL", RT5659_PWR_ANLG_3, RT5659_PWR_PLL_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5659_PWR_VOL,
+		RT5659_PWR_MIC_DET_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Mono Vref", RT5659_PWR_ANLG_1,
+		RT5659_PWR_VREF3_BIT, 0, NULL, 0),
+
+	/* ASRC */
+	SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5659_ASRC_1,
+		RT5659_I2S1_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5659_ASRC_1,
+		RT5659_I2S2_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5659_ASRC_1,
+		RT5659_I2S3_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5659_ASRC_1,
+		RT5659_DAC_STO_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC Mono L ASRC", 1, RT5659_ASRC_1,
+		RT5659_DAC_MONO_L_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC Mono R ASRC", 1, RT5659_ASRC_1,
+		RT5659_DAC_MONO_R_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5659_ASRC_1,
+		RT5659_ADC_STO1_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC Mono L ASRC", 1, RT5659_ASRC_1,
+		RT5659_ADC_MONO_L_ASRC_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ADC Mono R ASRC", 1, RT5659_ASRC_1,
+		RT5659_ADC_MONO_R_ASRC_SFT, 0, NULL, 0),
+
+	/* Input Side */
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5659_PWR_ANLG_2, RT5659_PWR_MB1_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5659_PWR_ANLG_2, RT5659_PWR_MB2_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS3", RT5659_PWR_ANLG_2, RT5659_PWR_MB3_BIT,
+		0, NULL, 0),
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("DMIC L1"),
+	SND_SOC_DAPM_INPUT("DMIC R1"),
+	SND_SOC_DAPM_INPUT("DMIC L2"),
+	SND_SOC_DAPM_INPUT("DMIC R2"),
+
+	SND_SOC_DAPM_INPUT("IN1P"),
+	SND_SOC_DAPM_INPUT("IN1N"),
+	SND_SOC_DAPM_INPUT("IN2P"),
+	SND_SOC_DAPM_INPUT("IN2N"),
+	SND_SOC_DAPM_INPUT("IN3P"),
+	SND_SOC_DAPM_INPUT("IN3N"),
+	SND_SOC_DAPM_INPUT("IN4P"),
+	SND_SOC_DAPM_INPUT("IN4N"),
+
+	SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+		set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5659_DMIC_CTRL_1,
+		RT5659_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5659_DMIC_CTRL_1,
+		RT5659_DMIC_2_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+
+	/* Boost */
+	SND_SOC_DAPM_PGA("BST1", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST1_P_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST2", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST2_P_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST3", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST3_P_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("BST4", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST4_P_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST1 Power", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST2 Power", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST3 Power", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST3_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("BST4 Power", RT5659_PWR_ANLG_2,
+		RT5659_PWR_BST4_BIT, 0, NULL, 0),
+
+
+	/* Input Volume */
+	SND_SOC_DAPM_PGA("INL VOL", RT5659_PWR_VOL, RT5659_PWR_IN_L_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_PGA("INR VOL", RT5659_PWR_VOL, RT5659_PWR_IN_R_BIT,
+		0, NULL, 0),
+
+	/* REC Mixer */
+	SND_SOC_DAPM_MIXER("RECMIX1L", RT5659_PWR_MIXER, RT5659_PWR_RM1_L_BIT,
+		0, rt5659_rec1_l_mix, ARRAY_SIZE(rt5659_rec1_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIX1R", RT5659_PWR_MIXER, RT5659_PWR_RM1_R_BIT,
+		0, rt5659_rec1_r_mix, ARRAY_SIZE(rt5659_rec1_r_mix)),
+	SND_SOC_DAPM_MIXER("RECMIX2L", RT5659_PWR_MIXER, RT5659_PWR_RM2_L_BIT,
+		0, rt5659_rec2_l_mix, ARRAY_SIZE(rt5659_rec2_l_mix)),
+	SND_SOC_DAPM_MIXER("RECMIX2R", RT5659_PWR_MIXER, RT5659_PWR_RM2_R_BIT,
+		0, rt5659_rec2_r_mix, ARRAY_SIZE(rt5659_rec2_r_mix)),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC2 L", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC2 R", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5659_PWR_DIG_1,
+		RT5659_PWR_ADC_L1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5659_PWR_DIG_1,
+		RT5659_PWR_ADC_R1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC2 L Power", RT5659_PWR_DIG_2,
+		RT5659_PWR_ADC_L2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC2 R Power", RT5659_PWR_DIG_2,
+		RT5659_PWR_ADC_R2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC1 clock", SND_SOC_NOPM, 0, 0, set_adc_clk,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("ADC2 clock", SND_SOC_NOPM, 0, 0, set_adc_clk,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	/* ADC Mux */
+	SND_SOC_DAPM_MUX("Stereo1 DMIC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo1 DMIC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_dmic_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_adc1_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_adc1_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_adc2_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_adc2_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_adc_mux),
+	SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_sto1_adc_mux),
+	SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_adc_l2_mux),
+	SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_adc_r2_mux),
+	SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_adc_l1_mux),
+	SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_adc_r1_mux),
+	SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_dmic_l_mux),
+	SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_dmic_r_mux),
+	SND_SOC_DAPM_MUX("Mono ADC L Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_adc_l_mux),
+	SND_SOC_DAPM_MUX("Mono ADC R Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_mono_adc_r_mux),
+	/* ADC Mixer */
+	SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5659_PWR_DIG_2,
+		RT5659_PWR_ADC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5659_PWR_DIG_2,
+		RT5659_PWR_ADC_S2F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM,
+		0, 0, rt5659_sto1_adc_l_mix,
+		ARRAY_SIZE(rt5659_sto1_adc_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM,
+		0, 0, rt5659_sto1_adc_r_mix,
+		ARRAY_SIZE(rt5659_sto1_adc_r_mix)),
+	SND_SOC_DAPM_SUPPLY("ADC Mono Left Filter", RT5659_PWR_DIG_2,
+		RT5659_PWR_ADC_MF_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Mono ADC MIXL", RT5659_MONO_ADC_DIG_VOL,
+		RT5659_L_MUTE_SFT, 1, rt5659_mono_adc_l_mix,
+		ARRAY_SIZE(rt5659_mono_adc_l_mix)),
+	SND_SOC_DAPM_SUPPLY("ADC Mono Right Filter", RT5659_PWR_DIG_2,
+		RT5659_PWR_ADC_MF_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Mono ADC MIXR", RT5659_MONO_ADC_DIG_VOL,
+		RT5659_R_MUTE_SFT, 1, rt5659_mono_adc_r_mix,
+		ARRAY_SIZE(rt5659_mono_adc_r_mix)),
+
+	/* ADC PGA */
+	SND_SOC_DAPM_PGA("IF_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo2 ADC LR", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("Stereo1 ADC Volume L", RT5659_STO1_ADC_DIG_VOL,
+		RT5659_L_MUTE_SFT, 1, NULL, 0),
+	SND_SOC_DAPM_PGA("Stereo1 ADC Volume R", RT5659_STO1_ADC_DIG_VOL,
+		RT5659_R_MUTE_SFT, 1, NULL, 0),
+
+	/* Digital Interface */
+	SND_SOC_DAPM_SUPPLY("I2S1", RT5659_PWR_DIG_1, RT5659_PWR_I2S1_BIT,
+		0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC2", 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 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("I2S2", RT5659_PWR_DIG_1, RT5659_PWR_I2S2_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF2 ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("I2S3", RT5659_PWR_DIG_1, RT5659_PWR_I2S3_BIT, 0,
+		NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("IF3 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* Digital Interface Select */
+	SND_SOC_DAPM_PGA("TDM AD1:AD2:DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("TDM AD2:DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("TDM Data Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_rx_adc_dac_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_if2_adc_in_mux),
+	SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0,
+		&rt5659_if3_adc_in_mux),
+	SND_SOC_DAPM_MUX("IF1 01 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if1_01_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 23 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if1_23_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 45 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if1_45_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF1 67 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if1_67_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF2 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if2_dac_swap_mux),
+	SND_SOC_DAPM_MUX("IF2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if2_adc_swap_mux),
+	SND_SOC_DAPM_MUX("IF3 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if3_dac_swap_mux),
+	SND_SOC_DAPM_MUX("IF3 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+			&rt5659_if3_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),
+	SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF3RX", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF3TX", "AIF3 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,
+		rt5659_dac_l_mix, ARRAY_SIZE(rt5659_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
+		rt5659_dac_r_mix, ARRAY_SIZE(rt5659_dac_r_mix)),
+
+	/* DAC channel Mux */
+	SND_SOC_DAPM_MUX("DAC L1 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_l1_mux),
+	SND_SOC_DAPM_MUX("DAC R1 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_r1_mux),
+	SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_l2_mux),
+	SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_r2_mux),
+
+	SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0,
+		&rt5659_alg_dac_l1_mux),
+	SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0,
+		&rt5659_alg_dac_r1_mux),
+	SND_SOC_DAPM_MUX("DAC L2 Source", SND_SOC_NOPM, 0, 0,
+		&rt5659_alg_dac_l2_mux),
+	SND_SOC_DAPM_MUX("DAC R2 Source", SND_SOC_NOPM, 0, 0,
+		&rt5659_alg_dac_r2_mux),
+
+	/* DAC Mixer */
+	SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5659_PWR_DIG_2,
+		RT5659_PWR_DAC_S1F_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Mono Left Filter", RT5659_PWR_DIG_2,
+		RT5659_PWR_DAC_MF_L_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC Mono Right Filter", RT5659_PWR_DIG_2,
+		RT5659_PWR_DAC_MF_R_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5659_sto_dac_l_mix, ARRAY_SIZE(rt5659_sto_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5659_sto_dac_r_mix, ARRAY_SIZE(rt5659_sto_dac_r_mix)),
+	SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,
+		rt5659_mono_dac_l_mix, ARRAY_SIZE(rt5659_mono_dac_l_mix)),
+	SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0,
+		rt5659_mono_dac_r_mix, ARRAY_SIZE(rt5659_mono_dac_r_mix)),
+	SND_SOC_DAPM_MUX("DAC MIXL", SND_SOC_NOPM, 0, 0,
+		&rt5659_dig_dac_mixl_mux),
+	SND_SOC_DAPM_MUX("DAC MIXR", SND_SOC_NOPM, 0, 0,
+		&rt5659_dig_dac_mixr_mux),
+
+	/* DACs */
+	SND_SOC_DAPM_SUPPLY_S("DAC L1 Power", 1, RT5659_PWR_DIG_1,
+		RT5659_PWR_DAC_L1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("DAC R1 Power", 1, RT5659_PWR_DIG_1,
+		RT5659_PWR_DAC_R1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_SUPPLY("DAC L2 Power", RT5659_PWR_DIG_1,
+		RT5659_PWR_DAC_L2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DAC R2 Power", RT5659_PWR_DIG_1,
+		RT5659_PWR_DAC_R2_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_DAC("DAC L2", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC R2", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_PGA("DAC_REF", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* OUT Mixer */
+	SND_SOC_DAPM_MIXER("SPK MIXL", RT5659_PWR_MIXER, RT5659_PWR_SM_L_BIT,
+		0, rt5659_spk_l_mix, ARRAY_SIZE(rt5659_spk_l_mix)),
+	SND_SOC_DAPM_MIXER("SPK MIXR", RT5659_PWR_MIXER, RT5659_PWR_SM_R_BIT,
+		0, rt5659_spk_r_mix, ARRAY_SIZE(rt5659_spk_r_mix)),
+	SND_SOC_DAPM_MIXER("MONOVOL MIX", RT5659_PWR_MIXER, RT5659_PWR_MM_BIT,
+		0, rt5659_monovol_mix, ARRAY_SIZE(rt5659_monovol_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXL", RT5659_PWR_MIXER, RT5659_PWR_OM_L_BIT,
+		0, rt5659_out_l_mix, ARRAY_SIZE(rt5659_out_l_mix)),
+	SND_SOC_DAPM_MIXER("OUT MIXR", RT5659_PWR_MIXER, RT5659_PWR_OM_R_BIT,
+		0, rt5659_out_r_mix, ARRAY_SIZE(rt5659_out_r_mix)),
+
+	/* Output Volume */
+	SND_SOC_DAPM_SWITCH("SPKVOL L", RT5659_PWR_VOL, RT5659_PWR_SV_L_BIT, 0,
+		&spkvol_l_switch),
+	SND_SOC_DAPM_SWITCH("SPKVOL R", RT5659_PWR_VOL, RT5659_PWR_SV_R_BIT, 0,
+		&spkvol_r_switch),
+	SND_SOC_DAPM_SWITCH("MONOVOL", RT5659_PWR_VOL, RT5659_PWR_MV_BIT, 0,
+		&monovol_switch),
+	SND_SOC_DAPM_SWITCH("OUTVOL L", RT5659_PWR_VOL, RT5659_PWR_OV_L_BIT, 0,
+		&outvol_l_switch),
+	SND_SOC_DAPM_SWITCH("OUTVOL R", RT5659_PWR_VOL, RT5659_PWR_OV_R_BIT, 0,
+		&outvol_r_switch),
+
+	/* SPO/MONO/HPO/LOUT */
+	SND_SOC_DAPM_MIXER("SPO L MIX", SND_SOC_NOPM, 0, 0, rt5659_spo_l_mix,
+		ARRAY_SIZE(rt5659_spo_l_mix)),
+	SND_SOC_DAPM_MIXER("SPO R MIX", SND_SOC_NOPM, 0, 0, rt5659_spo_r_mix,
+		ARRAY_SIZE(rt5659_spo_r_mix)),
+	SND_SOC_DAPM_MIXER("Mono MIX", SND_SOC_NOPM, 0,	0, rt5659_mono_mix,
+		ARRAY_SIZE(rt5659_mono_mix)),
+	SND_SOC_DAPM_MIXER("LOUT L MIX", SND_SOC_NOPM, 0, 0, rt5659_lout_l_mix,
+		ARRAY_SIZE(rt5659_lout_l_mix)),
+	SND_SOC_DAPM_MIXER("LOUT R MIX", SND_SOC_NOPM, 0, 0, rt5659_lout_r_mix,
+		ARRAY_SIZE(rt5659_lout_r_mix)),
+
+	SND_SOC_DAPM_PGA_S("SPK Amp", 1, RT5659_PWR_DIG_1, RT5659_PWR_CLS_D_BIT,
+		0, rt5659_spk_event, SND_SOC_DAPM_POST_PMD |
+		SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_PGA_S("Mono Amp", 1, RT5659_PWR_ANLG_1, RT5659_PWR_MA_BIT,
+		0, rt5659_mono_event, SND_SOC_DAPM_POST_PMD |
+		SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5659_hp_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA("LOUT Amp", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0,
+		rt5659_charge_pump_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SWITCH("SPO Playback", SND_SOC_NOPM, 0, 0, &spo_switch),
+	SND_SOC_DAPM_SWITCH("Mono Playback", SND_SOC_NOPM, 0, 0,
+		&mono_switch),
+	SND_SOC_DAPM_SWITCH("HPO L Playback", SND_SOC_NOPM, 0, 0,
+		&hpo_l_switch),
+	SND_SOC_DAPM_SWITCH("HPO R Playback", SND_SOC_NOPM, 0, 0,
+		&hpo_r_switch),
+	SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0,
+		&lout_l_switch),
+	SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0,
+		&lout_r_switch),
+	SND_SOC_DAPM_SWITCH("PDM L Playback", SND_SOC_NOPM, 0, 0,
+		&pdm_l_switch),
+	SND_SOC_DAPM_SWITCH("PDM R Playback", SND_SOC_NOPM, 0, 0,
+		&pdm_r_switch),
+
+	/* PDM */
+	SND_SOC_DAPM_SUPPLY("PDM Power", RT5659_PWR_DIG_2,
+		RT5659_PWR_PDM1_BIT, 0, NULL, 0),
+	SND_SOC_DAPM_MUX("PDM L Mux", RT5659_PDM_OUT_CTRL,
+		RT5659_M_PDM1_L_SFT, 1, &rt5659_pdm_l_mux),
+	SND_SOC_DAPM_MUX("PDM R Mux", RT5659_PDM_OUT_CTRL,
+		RT5659_M_PDM1_R_SFT, 1, &rt5659_pdm_r_mux),
+
+	/* SPDIF */
+	SND_SOC_DAPM_MUX("SPDIF Mux", SND_SOC_NOPM, 0, 0, &rt5659_spdif_mux),
+
+	SND_SOC_DAPM_SUPPLY("SYS CLK DET", RT5659_CLK_DET, 3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("CLKDET", RT5659_CLK_DET, 0, 0, NULL, 0),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPOL"),
+	SND_SOC_DAPM_OUTPUT("HPOR"),
+	SND_SOC_DAPM_OUTPUT("SPOL"),
+	SND_SOC_DAPM_OUTPUT("SPOR"),
+	SND_SOC_DAPM_OUTPUT("LOUTL"),
+	SND_SOC_DAPM_OUTPUT("LOUTR"),
+	SND_SOC_DAPM_OUTPUT("MONOOUT"),
+	SND_SOC_DAPM_OUTPUT("PDML"),
+	SND_SOC_DAPM_OUTPUT("PDMR"),
+	SND_SOC_DAPM_OUTPUT("SPDIF"),
+};
+
+static const struct snd_soc_dapm_route rt5659_dapm_routes[] = {
+	/*PLL*/
+	{ "ADC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll },
+	{ "ADC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll },
+	{ "ADC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll },
+	{ "ADC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll },
+	{ "DAC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll },
+	{ "DAC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll },
+	{ "DAC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll },
+
+	/*ASRC*/
+	{ "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc },
+	{ "ADC Mono Left Filter", NULL, "ADC Mono L ASRC", is_using_asrc },
+	{ "ADC Mono Right Filter", NULL, "ADC Mono R ASRC", is_using_asrc },
+	{ "DAC Mono Left Filter", NULL, "DAC Mono L ASRC", is_using_asrc },
+	{ "DAC Mono Right Filter", NULL, "DAC Mono R ASRC", is_using_asrc },
+	{ "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc },
+
+	{ "SYS CLK DET", NULL, "CLKDET" },
+
+	{ "I2S1", NULL, "I2S1 ASRC" },
+	{ "I2S2", NULL, "I2S2 ASRC" },
+	{ "I2S3", NULL, "I2S3 ASRC" },
+
+	{ "IN1P", NULL, "LDO2" },
+	{ "IN2P", NULL, "LDO2" },
+	{ "IN3P", NULL, "LDO2" },
+	{ "IN4P", NULL, "LDO2" },
+
+	{ "DMIC1", NULL, "DMIC L1" },
+	{ "DMIC1", NULL, "DMIC R1" },
+	{ "DMIC2", NULL, "DMIC L2" },
+	{ "DMIC2", NULL, "DMIC R2" },
+
+	{ "BST1", NULL, "IN1P" },
+	{ "BST1", NULL, "IN1N" },
+	{ "BST1", NULL, "BST1 Power" },
+	{ "BST2", NULL, "IN2P" },
+	{ "BST2", NULL, "IN2N" },
+	{ "BST2", NULL, "BST2 Power" },
+	{ "BST3", NULL, "IN3P" },
+	{ "BST3", NULL, "IN3N" },
+	{ "BST3", NULL, "BST3 Power" },
+	{ "BST4", NULL, "IN4P" },
+	{ "BST4", NULL, "IN4N" },
+	{ "BST4", NULL, "BST4 Power" },
+
+	{ "INL VOL", NULL, "IN2P" },
+	{ "INR VOL", NULL, "IN2N" },
+
+	{ "RECMIX1L", "SPKVOLL Switch", "SPKVOL L" },
+	{ "RECMIX1L", "INL Switch", "INL VOL" },
+	{ "RECMIX1L", "BST4 Switch", "BST4" },
+	{ "RECMIX1L", "BST3 Switch", "BST3" },
+	{ "RECMIX1L", "BST2 Switch", "BST2" },
+	{ "RECMIX1L", "BST1 Switch", "BST1" },
+
+	{ "RECMIX1R", "HPOVOLR Switch", "HPO R Playback" },
+	{ "RECMIX1R", "INR Switch", "INR VOL" },
+	{ "RECMIX1R", "BST4 Switch", "BST4" },
+	{ "RECMIX1R", "BST3 Switch", "BST3" },
+	{ "RECMIX1R", "BST2 Switch", "BST2" },
+	{ "RECMIX1R", "BST1 Switch", "BST1" },
+
+	{ "RECMIX2L", "SPKVOLL Switch", "SPKVOL L" },
+	{ "RECMIX2L", "OUTVOLL Switch", "OUTVOL L" },
+	{ "RECMIX2L", "BST4 Switch", "BST4" },
+	{ "RECMIX2L", "BST3 Switch", "BST3" },
+	{ "RECMIX2L", "BST2 Switch", "BST2" },
+	{ "RECMIX2L", "BST1 Switch", "BST1" },
+
+	{ "RECMIX2R", "MONOVOL Switch", "MONOVOL" },
+	{ "RECMIX2R", "OUTVOLR Switch", "OUTVOL R" },
+	{ "RECMIX2R", "BST4 Switch", "BST4" },
+	{ "RECMIX2R", "BST3 Switch", "BST3" },
+	{ "RECMIX2R", "BST2 Switch", "BST2" },
+	{ "RECMIX2R", "BST1 Switch", "BST1" },
+
+	{ "ADC1 L", NULL, "RECMIX1L" },
+	{ "ADC1 L", NULL, "ADC1 L Power" },
+	{ "ADC1 L", NULL, "ADC1 clock" },
+	{ "ADC1 R", NULL, "RECMIX1R" },
+	{ "ADC1 R", NULL, "ADC1 R Power" },
+	{ "ADC1 R", NULL, "ADC1 clock" },
+
+	{ "ADC2 L", NULL, "RECMIX2L" },
+	{ "ADC2 L", NULL, "ADC2 L Power" },
+	{ "ADC2 L", NULL, "ADC2 clock" },
+	{ "ADC2 R", NULL, "RECMIX2R" },
+	{ "ADC2 R", NULL, "ADC2 R Power" },
+	{ "ADC2 R", NULL, "ADC2 clock" },
+
+	{ "DMIC L1", NULL, "DMIC CLK" },
+	{ "DMIC L1", NULL, "DMIC1 Power" },
+	{ "DMIC R1", NULL, "DMIC CLK" },
+	{ "DMIC R1", NULL, "DMIC1 Power" },
+	{ "DMIC L2", NULL, "DMIC CLK" },
+	{ "DMIC L2", NULL, "DMIC2 Power" },
+	{ "DMIC R2", NULL, "DMIC CLK" },
+	{ "DMIC R2", NULL, "DMIC2 Power" },
+
+	{ "Stereo1 DMIC L Mux", "DMIC1", "DMIC L1" },
+	{ "Stereo1 DMIC L Mux", "DMIC2", "DMIC L2" },
+
+	{ "Stereo1 DMIC R Mux", "DMIC1", "DMIC R1" },
+	{ "Stereo1 DMIC R Mux", "DMIC2", "DMIC R2" },
+
+	{ "Mono DMIC L Mux", "DMIC1 L", "DMIC L1" },
+	{ "Mono DMIC L Mux", "DMIC2 L", "DMIC L2" },
+
+	{ "Mono DMIC R Mux", "DMIC1 R", "DMIC R1" },
+	{ "Mono DMIC R Mux", "DMIC2 R", "DMIC R2" },
+
+	{ "Stereo1 ADC L Mux", "ADC1", "ADC1 L" },
+	{ "Stereo1 ADC L Mux", "ADC2", "ADC2 L" },
+	{ "Stereo1 ADC R Mux", "ADC1", "ADC1 R" },
+	{ "Stereo1 ADC R Mux", "ADC2", "ADC2 R" },
+
+	{ "Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux" },
+	{ "Stereo1 ADC L1 Mux", "DAC MIX", "DAC MIXL" },
+	{ "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC L Mux" },
+	{ "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" },
+
+	{ "Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux" },
+	{ "Stereo1 ADC R1 Mux", "DAC MIX", "DAC MIXR" },
+	{ "Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC R Mux" },
+	{ "Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR" },
+
+	{ "Mono ADC L Mux", "ADC1 L", "ADC1 L" },
+	{ "Mono ADC L Mux", "ADC1 R", "ADC1 R" },
+	{ "Mono ADC L Mux", "ADC2 L", "ADC2 L" },
+	{ "Mono ADC L Mux", "ADC2 R", "ADC2 R" },
+
+	{ "Mono ADC R Mux", "ADC1 L", "ADC1 L" },
+	{ "Mono ADC R Mux", "ADC1 R", "ADC1 R" },
+	{ "Mono ADC R Mux", "ADC2 L", "ADC2 L" },
+	{ "Mono ADC R Mux", "ADC2 R", "ADC2 R" },
+
+	{ "Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux" },
+	{ "Mono ADC L2 Mux", "Mono DAC MIXL", "Mono DAC MIXL" },
+	{ "Mono ADC L1 Mux", "Mono DAC MIXL", "Mono DAC MIXL" },
+	{ "Mono ADC L1 Mux", "ADC",  "Mono ADC L Mux" },
+
+	{ "Mono ADC R1 Mux", "Mono DAC MIXR", "Mono DAC MIXR" },
+	{ "Mono ADC R1 Mux", "ADC", "Mono ADC R Mux" },
+	{ "Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux" },
+	{ "Mono ADC R2 Mux", "Mono DAC MIXR", "Mono DAC MIXR" },
+
+	{ "Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux" },
+	{ "Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux" },
+	{ "Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter" },
+
+	{ "Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux" },
+	{ "Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux" },
+	{ "Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter" },
+
+	{ "Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux" },
+	{ "Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux" },
+	{ "Mono ADC MIXL", NULL, "ADC Mono Left Filter" },
+
+	{ "Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux" },
+	{ "Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux" },
+	{ "Mono ADC MIXR", NULL, "ADC Mono Right Filter" },
+
+	{ "Stereo1 ADC Volume L", NULL, "Stereo1 ADC MIXL" },
+	{ "Stereo1 ADC Volume R", NULL, "Stereo1 ADC MIXR" },
+
+	{ "IF_ADC1", NULL, "Stereo1 ADC Volume L" },
+	{ "IF_ADC1", NULL, "Stereo1 ADC Volume R" },
+	{ "IF_ADC2", NULL, "Mono ADC MIXL" },
+	{ "IF_ADC2", NULL, "Mono ADC MIXR" },
+
+	{ "TDM AD1:AD2:DAC", NULL, "IF_ADC1" },
+	{ "TDM AD1:AD2:DAC", NULL, "IF_ADC2" },
+	{ "TDM AD1:AD2:DAC", NULL, "DAC_REF" },
+	{ "TDM AD2:DAC", NULL, "IF_ADC2" },
+	{ "TDM AD2:DAC", NULL, "DAC_REF" },
+	{ "TDM Data Mux", "AD1:AD2:DAC:NUL", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD1:AD2:NUL:DAC", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD1:DAC:AD2:NUL", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD1:DAC:NUL:AD2", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD1:NUL:DAC:AD2", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD1:NUL:AD2:DAC", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD2:AD1:DAC:NUL", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD2:AD1:NUL:DAC", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD2:DAC:AD1:NUL", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD2:DAC:NUL:AD1", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD2:NUL:DAC:AD1", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "AD1:NUL:AD1:DAC", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "DAC:AD1:AD2:NUL", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "DAC:AD1:NUL:AD2", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "DAC:AD2:AD1:NUL", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "DAC:AD2:NUL:AD1", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "DAC:NUL:DAC:AD2", "TDM AD2:DAC" },
+	{ "TDM Data Mux", "DAC:NUL:AD2:DAC", "TDM AD2:DAC" },
+	{ "TDM Data Mux", "NUL:AD1:AD2:DAC", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "NUL:AD1:DAC:AD2", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "NUL:AD2:AD1:DAC", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "NUL:AD2:DAC:AD1", "TDM AD1:AD2:DAC" },
+	{ "TDM Data Mux", "NUL:DAC:DAC:AD2", "TDM AD2:DAC" },
+	{ "TDM Data Mux", "NUL:DAC:AD2:DAC", "TDM AD2:DAC" },
+	{ "IF1 01 ADC Swap Mux", "L/R", "TDM Data Mux" },
+	{ "IF1 01 ADC Swap Mux", "R/L", "TDM Data Mux" },
+	{ "IF1 01 ADC Swap Mux", "L/L", "TDM Data Mux" },
+	{ "IF1 01 ADC Swap Mux", "R/R", "TDM Data Mux" },
+	{ "IF1 23 ADC Swap Mux", "L/R", "TDM Data Mux" },
+	{ "IF1 23 ADC Swap Mux", "R/L", "TDM Data Mux" },
+	{ "IF1 23 ADC Swap Mux", "L/L", "TDM Data Mux" },
+	{ "IF1 23 ADC Swap Mux", "R/R", "TDM Data Mux" },
+	{ "IF1 45 ADC Swap Mux", "L/R", "TDM Data Mux" },
+	{ "IF1 45 ADC Swap Mux", "R/L", "TDM Data Mux" },
+	{ "IF1 45 ADC Swap Mux", "L/L", "TDM Data Mux" },
+	{ "IF1 45 ADC Swap Mux", "R/R", "TDM Data Mux" },
+	{ "IF1 67 ADC Swap Mux", "L/R", "TDM Data Mux" },
+	{ "IF1 67 ADC Swap Mux", "R/L", "TDM Data Mux" },
+	{ "IF1 67 ADC Swap Mux", "L/L", "TDM Data Mux" },
+	{ "IF1 67 ADC Swap Mux", "R/R", "TDM Data Mux" },
+	{ "IF1 ADC", NULL, "IF1 01 ADC Swap Mux" },
+	{ "IF1 ADC", NULL, "IF1 23 ADC Swap Mux" },
+	{ "IF1 ADC", NULL, "IF1 45 ADC Swap Mux" },
+	{ "IF1 ADC", NULL, "IF1 67 ADC Swap Mux" },
+	{ "IF1 ADC", NULL, "I2S1" },
+
+	{ "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" },
+	{ "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" },
+	{ "IF2 ADC Mux", "IF_ADC3", "IF_ADC3" },
+	{ "IF2 ADC Mux", "DAC_REF", "DAC_REF" },
+	{ "IF2 ADC", NULL, "IF2 ADC Mux"},
+	{ "IF2 ADC", NULL, "I2S2" },
+
+	{ "IF3 ADC Mux", "IF_ADC1", "IF_ADC1" },
+	{ "IF3 ADC Mux", "IF_ADC2", "IF_ADC2" },
+	{ "IF3 ADC Mux", "Stereo2_ADC_L/R", "Stereo2 ADC LR" },
+	{ "IF3 ADC Mux", "DAC_REF", "DAC_REF" },
+	{ "IF3 ADC", NULL, "IF3 ADC Mux"},
+	{ "IF3 ADC", NULL, "I2S3" },
+
+	{ "AIF1TX", NULL, "IF1 ADC" },
+	{ "IF2 ADC Swap Mux", "L/R", "IF2 ADC" },
+	{ "IF2 ADC Swap Mux", "R/L", "IF2 ADC" },
+	{ "IF2 ADC Swap Mux", "L/L", "IF2 ADC" },
+	{ "IF2 ADC Swap Mux", "R/R", "IF2 ADC" },
+	{ "AIF2TX", NULL, "IF2 ADC Swap Mux" },
+	{ "IF3 ADC Swap Mux", "L/R", "IF3 ADC" },
+	{ "IF3 ADC Swap Mux", "R/L", "IF3 ADC" },
+	{ "IF3 ADC Swap Mux", "L/L", "IF3 ADC" },
+	{ "IF3 ADC Swap Mux", "R/R", "IF3 ADC" },
+	{ "AIF3TX", NULL, "IF3 ADC Swap Mux" },
+
+	{ "IF1 DAC1", NULL, "AIF1RX" },
+	{ "IF1 DAC2", NULL, "AIF1RX" },
+	{ "IF2 DAC Swap Mux", "L/R", "AIF2RX" },
+	{ "IF2 DAC Swap Mux", "R/L", "AIF2RX" },
+	{ "IF2 DAC Swap Mux", "L/L", "AIF2RX" },
+	{ "IF2 DAC Swap Mux", "R/R", "AIF2RX" },
+	{ "IF2 DAC", NULL, "IF2 DAC Swap Mux" },
+	{ "IF3 DAC Swap Mux", "L/R", "AIF3RX" },
+	{ "IF3 DAC Swap Mux", "R/L", "AIF3RX" },
+	{ "IF3 DAC Swap Mux", "L/L", "AIF3RX" },
+	{ "IF3 DAC Swap Mux", "R/R", "AIF3RX" },
+	{ "IF3 DAC", NULL, "IF3 DAC Swap Mux" },
+
+	{ "IF1 DAC1", NULL, "I2S1" },
+	{ "IF1 DAC2", NULL, "I2S1" },
+	{ "IF2 DAC", NULL, "I2S2" },
+	{ "IF3 DAC", NULL, "I2S3" },
+
+	{ "IF1 DAC2 L", NULL, "IF1 DAC2" },
+	{ "IF1 DAC2 R", NULL, "IF1 DAC2" },
+	{ "IF1 DAC1 L", NULL, "IF1 DAC1" },
+	{ "IF1 DAC1 R", NULL, "IF1 DAC1" },
+	{ "IF2 DAC L", NULL, "IF2 DAC" },
+	{ "IF2 DAC R", NULL, "IF2 DAC" },
+	{ "IF3 DAC L", NULL, "IF3 DAC" },
+	{ "IF3 DAC R", NULL, "IF3 DAC" },
+
+	{ "DAC L1 Mux", "IF1 DAC1", "IF1 DAC1 L" },
+	{ "DAC L1 Mux", "IF2 DAC", "IF2 DAC L" },
+	{ "DAC L1 Mux", "IF3 DAC", "IF3 DAC L" },
+	{ "DAC L1 Mux", NULL, "DAC Stereo1 Filter" },
+
+	{ "DAC R1 Mux", "IF1 DAC1", "IF1 DAC1 R" },
+	{ "DAC R1 Mux", "IF2 DAC", "IF2 DAC R" },
+	{ "DAC R1 Mux", "IF3 DAC", "IF3 DAC R" },
+	{ "DAC R1 Mux", NULL, "DAC Stereo1 Filter" },
+
+	{ "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC Volume L" },
+	{ "DAC1 MIXL", "DAC1 Switch", "DAC L1 Mux" },
+	{ "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC Volume R" },
+	{ "DAC1 MIXR", "DAC1 Switch", "DAC R1 Mux" },
+
+	{ "DAC_REF", NULL, "DAC1 MIXL" },
+	{ "DAC_REF", NULL, "DAC1 MIXR" },
+
+	{ "DAC L2 Mux", "IF1 DAC2", "IF1 DAC2 L" },
+	{ "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" },
+	{ "DAC L2 Mux", "IF3 DAC", "IF3 DAC L" },
+	{ "DAC L2 Mux", "Mono ADC MIX", "Mono ADC MIXL" },
+	{ "DAC L2 Mux", NULL, "DAC Mono Left Filter" },
+
+	{ "DAC R2 Mux", "IF1 DAC2", "IF1 DAC2 R" },
+	{ "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" },
+	{ "DAC R2 Mux", "IF3 DAC", "IF3 DAC R" },
+	{ "DAC R2 Mux", "Mono ADC MIX", "Mono ADC MIXR" },
+	{ "DAC R2 Mux", NULL, "DAC Mono Right Filter" },
+
+	{ "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux" },
+	{ "Stereo DAC MIXL", "DAC R2 Switch", "DAC R2 Mux" },
+
+	{ "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Stereo DAC MIXR", "DAC L2 Switch", "DAC L2 Mux" },
+	{ "Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux" },
+
+	{ "Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Mono DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux" },
+	{ "Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux" },
+	{ "Mono DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" },
+	{ "Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" },
+	{ "Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux" },
+	{ "Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux" },
+
+	{ "DAC MIXL", "Stereo DAC Mixer", "Stereo DAC MIXL" },
+	{ "DAC MIXL", "Mono DAC Mixer", "Mono DAC MIXL" },
+	{ "DAC MIXR", "Stereo DAC Mixer", "Stereo DAC MIXR" },
+	{ "DAC MIXR", "Mono DAC Mixer", "Mono DAC MIXR" },
+
+	{ "DAC L1 Source", NULL, "DAC L1 Power" },
+	{ "DAC L1 Source", "DAC", "DAC1 MIXL" },
+	{ "DAC L1 Source", "Stereo DAC Mixer", "Stereo DAC MIXL" },
+	{ "DAC R1 Source", NULL, "DAC R1 Power" },
+	{ "DAC R1 Source", "DAC", "DAC1 MIXR" },
+	{ "DAC R1 Source", "Stereo DAC Mixer", "Stereo DAC MIXR" },
+	{ "DAC L2 Source", "Stereo DAC Mixer", "Stereo DAC MIXL" },
+	{ "DAC L2 Source", "Mono DAC Mixer", "Mono DAC MIXL" },
+	{ "DAC L2 Source", NULL, "DAC L2 Power" },
+	{ "DAC R2 Source", "Stereo DAC Mixer", "Stereo DAC MIXR" },
+	{ "DAC R2 Source", "Mono DAC Mixer", "Mono DAC MIXR" },
+	{ "DAC R2 Source", NULL, "DAC R2 Power" },
+
+	{ "DAC L1", NULL, "DAC L1 Source" },
+	{ "DAC R1", NULL, "DAC R1 Source" },
+	{ "DAC L2", NULL, "DAC L2 Source" },
+	{ "DAC R2", NULL, "DAC R2 Source" },
+
+	{ "SPK MIXL", "DAC L2 Switch", "DAC L2" },
+	{ "SPK MIXL", "BST1 Switch", "BST1" },
+	{ "SPK MIXL", "INL Switch", "INL VOL" },
+	{ "SPK MIXL", "INR Switch", "INR VOL" },
+	{ "SPK MIXL", "BST3 Switch", "BST3" },
+	{ "SPK MIXR", "DAC R2 Switch", "DAC R2" },
+	{ "SPK MIXR", "BST4 Switch", "BST4" },
+	{ "SPK MIXR", "INL Switch", "INL VOL" },
+	{ "SPK MIXR", "INR Switch", "INR VOL" },
+	{ "SPK MIXR", "BST3 Switch", "BST3" },
+
+	{ "MONOVOL MIX", "DAC L2 Switch", "DAC L2" },
+	{ "MONOVOL MIX", "DAC R2 Switch", "DAC R2" },
+	{ "MONOVOL MIX", "BST1 Switch", "BST1" },
+	{ "MONOVOL MIX", "BST2 Switch", "BST2" },
+	{ "MONOVOL MIX", "BST3 Switch", "BST3" },
+
+	{ "OUT MIXL", "DAC L2 Switch", "DAC L2" },
+	{ "OUT MIXL", "INL Switch", "INL VOL" },
+	{ "OUT MIXL", "BST1 Switch", "BST1" },
+	{ "OUT MIXL", "BST2 Switch", "BST2" },
+	{ "OUT MIXL", "BST3 Switch", "BST3" },
+	{ "OUT MIXR", "DAC R2 Switch", "DAC R2" },
+	{ "OUT MIXR", "INR Switch", "INR VOL" },
+	{ "OUT MIXR", "BST2 Switch", "BST2" },
+	{ "OUT MIXR", "BST3 Switch", "BST3" },
+	{ "OUT MIXR", "BST4 Switch", "BST4" },
+
+	{ "SPKVOL L", "Switch", "SPK MIXL" },
+	{ "SPKVOL R", "Switch", "SPK MIXR" },
+	{ "SPO L MIX", "DAC L2 Switch", "DAC L2" },
+	{ "SPO L MIX", "SPKVOL L Switch", "SPKVOL L" },
+	{ "SPO R MIX", "DAC R2 Switch", "DAC R2" },
+	{ "SPO R MIX", "SPKVOL R Switch", "SPKVOL R" },
+	{ "SPK Amp", NULL, "SPO L MIX" },
+	{ "SPK Amp", NULL, "SPO R MIX" },
+	{ "SPK Amp", NULL, "SYS CLK DET" },
+	{ "SPO Playback", "Switch", "SPK Amp" },
+	{ "SPOL", NULL, "SPO Playback" },
+	{ "SPOR", NULL, "SPO Playback" },
+
+	{ "MONOVOL", "Switch", "MONOVOL MIX" },
+	{ "Mono MIX", "DAC L2 Switch", "DAC L2" },
+	{ "Mono MIX", "MONOVOL Switch", "MONOVOL" },
+	{ "Mono Amp", NULL, "Mono MIX" },
+	{ "Mono Amp", NULL, "Mono Vref" },
+	{ "Mono Amp", NULL, "SYS CLK DET" },
+	{ "Mono Playback", "Switch", "Mono Amp" },
+	{ "MONOOUT", NULL, "Mono Playback" },
+
+	{ "HP Amp", NULL, "DAC L1" },
+	{ "HP Amp", NULL, "DAC R1" },
+	{ "HP Amp", NULL, "Charge Pump" },
+	{ "HP Amp", NULL, "SYS CLK DET" },
+	{ "HPO L Playback", "Switch", "HP Amp"},
+	{ "HPO R Playback", "Switch", "HP Amp"},
+	{ "HPOL", NULL, "HPO L Playback" },
+	{ "HPOR", NULL, "HPO R Playback" },
+
+	{ "OUTVOL L", "Switch", "OUT MIXL" },
+	{ "OUTVOL R", "Switch", "OUT MIXR" },
+	{ "LOUT L MIX", "DAC L2 Switch", "DAC L2" },
+	{ "LOUT L MIX", "OUTVOL L Switch", "OUTVOL L" },
+	{ "LOUT R MIX", "DAC R2 Switch", "DAC R2" },
+	{ "LOUT R MIX", "OUTVOL R Switch", "OUTVOL R" },
+	{ "LOUT Amp", NULL, "LOUT L MIX" },
+	{ "LOUT Amp", NULL, "LOUT R MIX" },
+	{ "LOUT Amp", NULL, "SYS CLK DET" },
+	{ "LOUT L Playback", "Switch", "LOUT Amp" },
+	{ "LOUT R Playback", "Switch", "LOUT Amp" },
+	{ "LOUTL", NULL, "LOUT L Playback" },
+	{ "LOUTR", NULL, "LOUT R Playback" },
+
+	{ "PDM L Mux", "Mono DAC", "Mono DAC MIXL" },
+	{ "PDM L Mux", "Stereo DAC", "Stereo DAC MIXL" },
+	{ "PDM L Mux", NULL, "PDM Power" },
+	{ "PDM R Mux", "Mono DAC", "Mono DAC MIXR" },
+	{ "PDM R Mux", "Stereo DAC", "Stereo DAC MIXR" },
+	{ "PDM R Mux", NULL, "PDM Power" },
+	{ "PDM L Playback", "Switch", "PDM L Mux" },
+	{ "PDM R Playback", "Switch", "PDM R Mux" },
+	{ "PDML", NULL, "PDM L Playback" },
+	{ "PDMR", NULL, "PDM R Playback" },
+
+	{ "SPDIF Mux", "IF3_DAC", "IF3 DAC" },
+	{ "SPDIF Mux", "IF2_DAC", "IF2 DAC" },
+	{ "SPDIF Mux", "IF1_DAC2", "IF1 DAC2" },
+	{ "SPDIF Mux", "IF1_DAC1", "IF1 DAC1" },
+	{ "SPDIF", NULL, "SPDIF Mux" },
+};
+
+static int rt5659_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 rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	unsigned int val_len = 0, val_clk, mask_clk;
+	int pre_div, frame_size;
+
+	rt5659->lrck[dai->id] = params_rate(params);
+	pre_div = rl6231_get_clk_info(rt5659->sysclk, rt5659->lrck[dai->id]);
+	if (pre_div < 0) {
+		dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
+			rt5659->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 -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
+				rt5659->lrck[dai->id], pre_div, dai->id);
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		val_len |= RT5659_I2S_DL_20;
+		break;
+	case 24:
+		val_len |= RT5659_I2S_DL_24;
+		break;
+	case 8:
+		val_len |= RT5659_I2S_DL_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5659_AIF1:
+		mask_clk = RT5659_I2S_PD1_MASK;
+		val_clk = pre_div << RT5659_I2S_PD1_SFT;
+		snd_soc_update_bits(codec, RT5659_I2S1_SDP,
+			RT5659_I2S_DL_MASK, val_len);
+		break;
+	case RT5659_AIF2:
+		mask_clk = RT5659_I2S_PD2_MASK;
+		val_clk = pre_div << RT5659_I2S_PD2_SFT;
+		snd_soc_update_bits(codec, RT5659_I2S2_SDP,
+			RT5659_I2S_DL_MASK, val_len);
+		break;
+	case RT5659_AIF3:
+		mask_clk = RT5659_I2S_PD3_MASK;
+		val_clk = pre_div << RT5659_I2S_PD3_SFT;
+		snd_soc_update_bits(codec, RT5659_I2S3_SDP,
+			RT5659_I2S_DL_MASK, val_len);
+		break;
+	default:
+		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, mask_clk, val_clk);
+
+	switch (rt5659->lrck[dai->id]) {
+	case 192000:
+		snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+			RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_32);
+		break;
+	case 96000:
+		snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+			RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_64);
+		break;
+	default:
+		snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+			RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_128);
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5659_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	unsigned int reg_val = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rt5659->master[dai->id] = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		reg_val |= RT5659_I2S_MS_S;
+		rt5659->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 |= RT5659_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 |= RT5659_I2S_DF_LEFT;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		reg_val |= RT5659_I2S_DF_PCM_A;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		reg_val |= RT5659_I2S_DF_PCM_B;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case RT5659_AIF1:
+		snd_soc_update_bits(codec, RT5659_I2S1_SDP,
+			RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK |
+			RT5659_I2S_DF_MASK, reg_val);
+		break;
+	case RT5659_AIF2:
+		snd_soc_update_bits(codec, RT5659_I2S2_SDP,
+			RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK |
+			RT5659_I2S_DF_MASK, reg_val);
+		break;
+	case RT5659_AIF3:
+		snd_soc_update_bits(codec, RT5659_I2S3_SDP,
+			RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK |
+			RT5659_I2S_DF_MASK, reg_val);
+		break;
+	default:
+		dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int rt5659_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	unsigned int reg_val = 0;
+
+	if (freq == rt5659->sysclk && clk_id == rt5659->sysclk_src)
+		return 0;
+
+	switch (clk_id) {
+	case RT5659_SCLK_S_MCLK:
+		reg_val |= RT5659_SCLK_SRC_MCLK;
+		break;
+	case RT5659_SCLK_S_PLL1:
+		reg_val |= RT5659_SCLK_SRC_PLL1;
+		break;
+	case RT5659_SCLK_S_RCCLK:
+		reg_val |= RT5659_SCLK_SRC_RCCLK;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+		return -EINVAL;
+	}
+	snd_soc_update_bits(codec, RT5659_GLB_CLK,
+		RT5659_SCLK_SRC_MASK, reg_val);
+	rt5659->sysclk = freq;
+	rt5659->sysclk_src = clk_id;
+
+	dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+	return 0;
+}
+
+static int rt5659_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 rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+	struct rl6231_pll_code pll_code;
+	int ret;
+
+	if (Source == rt5659->pll_src && freq_in == rt5659->pll_in &&
+	    freq_out == rt5659->pll_out)
+		return 0;
+
+	if (!freq_in || !freq_out) {
+		dev_dbg(codec->dev, "PLL disabled\n");
+
+		rt5659->pll_in = 0;
+		rt5659->pll_out = 0;
+		snd_soc_update_bits(codec, RT5659_GLB_CLK,
+			RT5659_SCLK_SRC_MASK, RT5659_SCLK_SRC_MCLK);
+		return 0;
+	}
+
+	switch (Source) {
+	case RT5659_PLL1_S_MCLK:
+		snd_soc_update_bits(codec, RT5659_GLB_CLK,
+			RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_MCLK);
+		break;
+	case RT5659_PLL1_S_BCLK1:
+		snd_soc_update_bits(codec, RT5659_GLB_CLK,
+				RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK1);
+		break;
+	case RT5659_PLL1_S_BCLK2:
+		snd_soc_update_bits(codec, RT5659_GLB_CLK,
+				RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK2);
+		break;
+	case RT5659_PLL1_S_BCLK3:
+		snd_soc_update_bits(codec, RT5659_GLB_CLK,
+				RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK3);
+		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, RT5659_PLL_CTRL_1,
+		pll_code.n_code << RT5659_PLL_N_SFT | pll_code.k_code);
+	snd_soc_write(codec, RT5659_PLL_CTRL_2,
+		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5659_PLL_M_SFT |
+		pll_code.m_bp << RT5659_PLL_M_BP_SFT);
+
+	rt5659->pll_in = freq_in;
+	rt5659->pll_out = freq_out;
+	rt5659->pll_src = Source;
+
+	return 0;
+}
+
+static int rt5659_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+			unsigned int rx_mask, int slots, int slot_width)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned int val = 0;
+
+	if (rx_mask || tx_mask)
+		val |= (1 << 15);
+
+	switch (slots) {
+	case 4:
+		val |= (1 << 10);
+		val |= (1 << 8);
+		break;
+	case 6:
+		val |= (2 << 10);
+		val |= (2 << 8);
+		break;
+	case 8:
+		val |= (3 << 10);
+		val |= (3 << 8);
+		break;
+	case 2:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (slot_width) {
+	case 20:
+		val |= (1 << 6);
+		val |= (1 << 4);
+		break;
+	case 24:
+		val |= (2 << 6);
+		val |= (2 << 4);
+		break;
+	case 32:
+		val |= (3 << 6);
+		val |= (3 << 4);
+		break;
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, RT5659_TDM_CTRL_1, 0x8ff0, val);
+
+	return 0;
+}
+
+static int rt5659_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio);
+
+	rt5659->bclk[dai->id] = ratio;
+
+	if (ratio == 64) {
+		switch (dai->id) {
+		case RT5659_AIF2:
+			snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+				RT5659_I2S_BCLK_MS2_MASK,
+				RT5659_I2S_BCLK_MS2_64);
+			break;
+		case RT5659_AIF3:
+			snd_soc_update_bits(codec, RT5659_ADDA_CLK_1,
+				RT5659_I2S_BCLK_MS3_MASK,
+				RT5659_I2S_BCLK_MS3_64);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int rt5659_set_bias_level(struct snd_soc_codec *codec,
+			enum snd_soc_bias_level level)
+{
+	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+	switch (level) {
+	case SND_SOC_BIAS_PREPARE:
+		regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC,
+			RT5659_DIG_GATE_CTRL, RT5659_DIG_GATE_CTRL);
+		regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1,
+			RT5659_PWR_LDO,	RT5659_PWR_LDO);
+		regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+			RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2,
+			RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2);
+		msleep(20);
+		regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+			RT5659_PWR_FV1 | RT5659_PWR_FV2,
+			RT5659_PWR_FV1 | RT5659_PWR_FV2);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1,
+			RT5659_PWR_LDO, 0);
+		regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+			RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2
+			| RT5659_PWR_FV1 | RT5659_PWR_FV2,
+			RT5659_PWR_MB | RT5659_PWR_VREF2);
+		regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC,
+			RT5659_DIG_GATE_CTRL, 0);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int rt5659_probe(struct snd_soc_codec *codec)
+{
+	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+	rt5659->codec = codec;
+
+	return 0;
+}
+
+static int rt5659_remove(struct snd_soc_codec *codec)
+{
+	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+	regmap_write(rt5659->regmap, RT5659_RESET, 0);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5659_suspend(struct snd_soc_codec *codec)
+{
+	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+	regcache_cache_only(rt5659->regmap, true);
+	regcache_mark_dirty(rt5659->regmap);
+	return 0;
+}
+
+static int rt5659_resume(struct snd_soc_codec *codec)
+{
+	struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
+
+	regcache_cache_only(rt5659->regmap, false);
+	regcache_sync(rt5659->regmap);
+
+	return 0;
+}
+#else
+#define rt5659_suspend NULL
+#define rt5659_resume NULL
+#endif
+
+#define RT5659_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5659_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 rt5659_aif_dai_ops = {
+	.hw_params = rt5659_hw_params,
+	.set_fmt = rt5659_set_dai_fmt,
+	.set_sysclk = rt5659_set_dai_sysclk,
+	.set_tdm_slot = rt5659_set_tdm_slot,
+	.set_pll = rt5659_set_dai_pll,
+	.set_bclk_ratio = rt5659_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt5659_dai[] = {
+	{
+		.name = "rt5659-aif1",
+		.id = RT5659_AIF1,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5659_STEREO_RATES,
+			.formats = RT5659_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5659_STEREO_RATES,
+			.formats = RT5659_FORMATS,
+		},
+		.ops = &rt5659_aif_dai_ops,
+	},
+	{
+		.name = "rt5659-aif2",
+		.id = RT5659_AIF2,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5659_STEREO_RATES,
+			.formats = RT5659_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5659_STEREO_RATES,
+			.formats = RT5659_FORMATS,
+		},
+		.ops = &rt5659_aif_dai_ops,
+	},
+	{
+		.name = "rt5659-aif3",
+		.id = RT5659_AIF3,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5659_STEREO_RATES,
+			.formats = RT5659_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF3 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = RT5659_STEREO_RATES,
+			.formats = RT5659_FORMATS,
+		},
+		.ops = &rt5659_aif_dai_ops,
+	},
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5659 = {
+	.probe = rt5659_probe,
+	.remove = rt5659_remove,
+	.suspend = rt5659_suspend,
+	.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),
+};
+
+
+static const struct regmap_config rt5659_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+	.max_register = 0x0400,
+	.volatile_reg = rt5659_volatile_register,
+	.readable_reg = rt5659_readable_register,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults = rt5659_reg,
+	.num_reg_defaults = ARRAY_SIZE(rt5659_reg),
+};
+
+static const struct i2c_device_id rt5659_i2c_id[] = {
+	{ "rt5658", 0 },
+	{ "rt5659", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rt5659_i2c_id);
+
+static int rt5659_parse_dt(struct rt5659_priv *rt5659, struct device *dev)
+{
+	rt5659->pdata.in1_diff = device_property_read_bool(dev,
+					"realtek,in1-differential");
+	rt5659->pdata.in3_diff = device_property_read_bool(dev,
+					"realtek,in3-differential");
+	rt5659->pdata.in4_diff = device_property_read_bool(dev,
+					"realtek,in4-differential");
+
+
+	device_property_read_u32(dev, "realtek,dmic1-data-pin",
+		&rt5659->pdata.dmic1_data_pin);
+	device_property_read_u32(dev, "realtek,dmic2-data-pin",
+		&rt5659->pdata.dmic2_data_pin);
+	device_property_read_u32(dev, "realtek,jd-src",
+		&rt5659->pdata.jd_src);
+
+	return 0;
+}
+
+static void rt5659_calibrate(struct rt5659_priv *rt5659)
+{
+	int value, count;
+
+	/* Calibrate HPO Start */
+	/* Fine tune HP Performance */
+	regmap_write(rt5659->regmap, RT5659_BIAS_CUR_CTRL_8, 0xa502);
+	regmap_write(rt5659->regmap, RT5659_CHOP_DAC, 0x3030);
+
+	regmap_write(rt5659->regmap, RT5659_PRE_DIV_1, 0xef00);
+	regmap_write(rt5659->regmap, RT5659_PRE_DIV_2, 0xeffc);
+	regmap_write(rt5659->regmap, RT5659_MICBIAS_2, 0x0280);
+	regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x0001);
+	regmap_write(rt5659->regmap, RT5659_GLB_CLK, 0x8000);
+
+	regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xaa7e);
+	msleep(60);
+	regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xfe7e);
+	msleep(50);
+	regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0004);
+	regmap_write(rt5659->regmap, RT5659_PWR_DIG_2, 0x0400);
+	msleep(50);
+	regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0080);
+	usleep_range(10000, 10005);
+	regmap_write(rt5659->regmap, RT5659_DEPOP_1, 0x0009);
+	msleep(50);
+	regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0f80);
+	msleep(50);
+	regmap_write(rt5659->regmap, RT5659_HP_CHARGE_PUMP_1, 0x0e16);
+	msleep(50);
+
+	/* Enalbe K ADC Power And Clock */
+	regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0505);
+	msleep(50);
+	regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0184);
+	regmap_write(rt5659->regmap, RT5659_CALIB_ADC_CTRL, 0x3c05);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c1);
+
+	/* K Headphone */
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x5100);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0014);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0xd100);
+	msleep(60);
+
+	/* Manual K ADC Offset */
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x4900);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0016);
+	regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_1,
+		0x8000, 0x8000);
+
+	count = 0;
+	while (true) {
+		regmap_read(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, &value);
+		if (value & 0x8000)
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (count > 30) {
+			dev_err(rt5659->codec->dev,
+				"HP Calibration 1 Failure\n");
+			return;
+		}
+
+		count++;
+	}
+
+	/* Manual K Internal Path Offset */
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1);
+	regmap_write(rt5659->regmap, RT5659_HP_VOL, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x4500);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x001f);
+	regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_1,
+		0x8000, 0x8000);
+
+	count = 0;
+	while (true) {
+		regmap_read(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, &value);
+		if (value & 0x8000)
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (count > 85) {
+			dev_err(rt5659->codec->dev,
+				"HP Calibration 2 Failure\n");
+			return;
+		}
+
+		count++;
+	}
+
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c0);
+	/* Calibrate HPO End */
+
+	/* Calibrate SPO Start */
+	regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x2021);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_CTRL_1, 0x0260);
+	regmap_write(rt5659->regmap, RT5659_PWR_MIXER, 0x3000);
+	regmap_write(rt5659->regmap, RT5659_PWR_VOL, 0xc000);
+	regmap_write(rt5659->regmap, RT5659_A_DAC_MUX, 0x000c);
+	regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x8000);
+	regmap_write(rt5659->regmap, RT5659_SPO_VOL, 0x0808);
+	regmap_write(rt5659->regmap, RT5659_SPK_L_MIXER, 0x001e);
+	regmap_write(rt5659->regmap, RT5659_SPK_R_MIXER, 0x001e);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_1, 0x0803);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_2, 0x0554);
+	regmap_write(rt5659->regmap, RT5659_SPO_AMP_GAIN, 0x1103);
+
+	/* Enalbe K ADC Power And Clock */
+	regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0909);
+	regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x0001,
+		0x0001);
+
+	/* Start Calibration */
+	regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x0021);
+	regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_1, 0x3e80);
+	regmap_update_bits(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_1,
+		0x8000, 0x8000);
+
+	count = 0;
+	while (true) {
+		regmap_read(rt5659->regmap,
+				RT5659_SPK_DC_CAILB_CTRL_1, &value);
+		if (value & 0x8000)
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (count > 10) {
+			dev_err(rt5659->codec->dev,
+				"SPK Calibration Failure\n");
+			return;
+		}
+
+		count++;
+	}
+	/* Calibrate SPO End */
+
+	/* Calibrate MONO Start */
+	regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_MONOMIX_IN_GAIN, 0x021f);
+	regmap_write(rt5659->regmap, RT5659_MONO_OUT, 0x480a);
+	/* MONO NG2 GAIN 5dB */
+	regmap_write(rt5659->regmap, RT5659_MONO_GAIN, 0x0003);
+	regmap_write(rt5659->regmap, RT5659_MONO_NG2_CTRL_5, 0x0009);
+
+	/* Start Calibration */
+	regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x000f);
+	regmap_write(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e00);
+	regmap_update_bits(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1,
+		0x8000, 0x8000);
+
+	count = 0;
+	while (true) {
+		regmap_read(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1,
+			&value);
+		if (value & 0x8000)
+			usleep_range(10000, 10005);
+		else
+			break;
+
+		if (count > 35) {
+			dev_err(rt5659->codec->dev,
+				"Mono Calibration Failure\n");
+			return;
+		}
+
+		count++;
+	}
+
+	regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x0003);
+	/* Calibrate MONO End */
+
+	/* Power Off */
+	regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0808);
+	regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_CALIB_ADC_CTRL, 0x2005);
+	regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c0);
+	regmap_write(rt5659->regmap, RT5659_DEPOP_1, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_1, 0x0011);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_2, 0x0150);
+	regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xfe3e);
+	regmap_write(rt5659->regmap, RT5659_MONO_OUT, 0xc80a);
+	regmap_write(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e04);
+	regmap_write(rt5659->regmap, RT5659_PWR_MIXER, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_PWR_VOL, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_PWR_DIG_2, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0x003e);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_CTRL_1, 0x0060);
+	regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x2021);
+	regmap_write(rt5659->regmap, RT5659_GLB_CLK, 0x0000);
+	regmap_write(rt5659->regmap, RT5659_MICBIAS_2, 0x0080);
+	regmap_write(rt5659->regmap, RT5659_HP_VOL, 0x8080);
+	regmap_write(rt5659->regmap, RT5659_HP_CHARGE_PUMP_1, 0x0c16);
+}
+
+static int rt5659_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct rt5659_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	struct rt5659_priv *rt5659;
+	int ret;
+	unsigned int val;
+
+	rt5659 = devm_kzalloc(&i2c->dev, sizeof(struct rt5659_priv),
+		GFP_KERNEL);
+
+	if (rt5659 == NULL)
+		return -ENOMEM;
+
+	rt5659->i2c = i2c;
+	i2c_set_clientdata(i2c, rt5659);
+
+	if (pdata)
+		rt5659->pdata = *pdata;
+	else
+		rt5659_parse_dt(rt5659, &i2c->dev);
+
+	rt5659->gpiod_ldo1_en = devm_gpiod_get_optional(&i2c->dev, "ldo1-en",
+							GPIOD_OUT_HIGH);
+	if (IS_ERR(rt5659->gpiod_ldo1_en))
+		dev_warn(&i2c->dev, "Request ldo1-en GPIO failed\n");
+
+	rt5659->gpiod_reset = devm_gpiod_get_optional(&i2c->dev, "reset",
+							GPIOD_OUT_HIGH);
+
+	/* Sleep for 300 ms miniumum */
+	usleep_range(300000, 350000);
+
+	rt5659->regmap = devm_regmap_init_i2c(i2c, &rt5659_regmap);
+	if (IS_ERR(rt5659->regmap)) {
+		ret = PTR_ERR(rt5659->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	regmap_read(rt5659->regmap, RT5659_DEVICE_ID, &val);
+	if (val != DEVICE_ID) {
+		dev_err(&i2c->dev,
+			"Device with ID register %x is not rt5659\n", val);
+		return -ENODEV;
+	}
+
+	regmap_write(rt5659->regmap, RT5659_RESET, 0);
+
+	rt5659_calibrate(rt5659);
+
+	/* line in diff mode*/
+	if (rt5659->pdata.in1_diff)
+		regmap_update_bits(rt5659->regmap, RT5659_IN1_IN2,
+			RT5659_IN1_DF_MASK, RT5659_IN1_DF_MASK);
+	if (rt5659->pdata.in3_diff)
+		regmap_update_bits(rt5659->regmap, RT5659_IN3_IN4,
+			RT5659_IN3_DF_MASK, RT5659_IN3_DF_MASK);
+	if (rt5659->pdata.in4_diff)
+		regmap_update_bits(rt5659->regmap, RT5659_IN3_IN4,
+			RT5659_IN4_DF_MASK, RT5659_IN4_DF_MASK);
+
+	/* DMIC pin*/
+	if (rt5659->pdata.dmic1_data_pin != RT5659_DMIC1_NULL ||
+		rt5659->pdata.dmic2_data_pin != RT5659_DMIC2_NULL) {
+		regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+			RT5659_GP2_PIN_MASK, RT5659_GP2_PIN_DMIC1_SCL);
+
+		switch (rt5659->pdata.dmic1_data_pin) {
+		case RT5659_DMIC1_DATA_IN2N:
+			regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_IN2N);
+			break;
+
+		case RT5659_DMIC1_DATA_GPIO5:
+			regmap_update_bits(rt5659->regmap,
+				RT5659_GPIO_CTRL_3,
+				RT5659_I2S2_PIN_MASK,
+				RT5659_I2S2_PIN_GPIO);
+			regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO5);
+			regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+				RT5659_GP5_PIN_MASK, RT5659_GP5_PIN_DMIC1_SDA);
+			break;
+
+		case RT5659_DMIC1_DATA_GPIO9:
+			regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO9);
+			regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+				RT5659_GP9_PIN_MASK, RT5659_GP9_PIN_DMIC1_SDA);
+			break;
+
+		case RT5659_DMIC1_DATA_GPIO11:
+			regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO11);
+			regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+				RT5659_GP11_PIN_MASK,
+				RT5659_GP11_PIN_DMIC1_SDA);
+			break;
+
+		default:
+			dev_dbg(&i2c->dev, "no DMIC1\n");
+			break;
+		}
+
+		switch (rt5659->pdata.dmic2_data_pin) {
+		case RT5659_DMIC2_DATA_IN2P:
+			regmap_update_bits(rt5659->regmap,
+				RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_2_DP_MASK,
+				RT5659_DMIC_2_DP_IN2P);
+			break;
+
+		case RT5659_DMIC2_DATA_GPIO6:
+			regmap_update_bits(rt5659->regmap,
+				RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_2_DP_MASK,
+				RT5659_DMIC_2_DP_GPIO6);
+			regmap_update_bits(rt5659->regmap,
+				RT5659_GPIO_CTRL_1,
+				RT5659_GP6_PIN_MASK,
+				RT5659_GP6_PIN_DMIC2_SDA);
+			break;
+
+		case RT5659_DMIC2_DATA_GPIO10:
+			regmap_update_bits(rt5659->regmap,
+				RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_2_DP_MASK,
+				RT5659_DMIC_2_DP_GPIO10);
+			regmap_update_bits(rt5659->regmap,
+				RT5659_GPIO_CTRL_1,
+				RT5659_GP10_PIN_MASK,
+				RT5659_GP10_PIN_DMIC2_SDA);
+			break;
+
+		case RT5659_DMIC2_DATA_GPIO12:
+			regmap_update_bits(rt5659->regmap,
+				RT5659_DMIC_CTRL_1,
+				RT5659_DMIC_2_DP_MASK,
+				RT5659_DMIC_2_DP_GPIO12);
+			regmap_update_bits(rt5659->regmap,
+				RT5659_GPIO_CTRL_1,
+				RT5659_GP12_PIN_MASK,
+				RT5659_GP12_PIN_DMIC2_SDA);
+			break;
+
+		default:
+			dev_dbg(&i2c->dev, "no DMIC2\n");
+			break;
+
+		}
+	} else {
+		regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1,
+			RT5659_GP2_PIN_MASK | RT5659_GP5_PIN_MASK |
+			RT5659_GP9_PIN_MASK | RT5659_GP11_PIN_MASK |
+			RT5659_GP6_PIN_MASK | RT5659_GP10_PIN_MASK |
+			RT5659_GP12_PIN_MASK,
+			RT5659_GP2_PIN_GPIO2 | RT5659_GP5_PIN_GPIO5 |
+			RT5659_GP9_PIN_GPIO9 | RT5659_GP11_PIN_GPIO11 |
+			RT5659_GP6_PIN_GPIO6 | RT5659_GP10_PIN_GPIO10 |
+			RT5659_GP12_PIN_GPIO12);
+		regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1,
+			RT5659_DMIC_1_DP_MASK | RT5659_DMIC_2_DP_MASK,
+			RT5659_DMIC_1_DP_IN2N | RT5659_DMIC_2_DP_IN2P);
+	}
+
+	switch (rt5659->pdata.jd_src) {
+	case RT5659_JD3:
+		regmap_write(rt5659->regmap, RT5659_EJD_CTRL_1, 0xa880);
+		regmap_write(rt5659->regmap, RT5659_RC_CLK_CTRL, 0x9000);
+		regmap_write(rt5659->regmap, RT5659_GPIO_CTRL_1, 0xc800);
+		regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1,
+				RT5659_PWR_MB, RT5659_PWR_MB);
+		regmap_write(rt5659->regmap, RT5659_PWR_ANLG_2, 0x0001);
+		regmap_write(rt5659->regmap, RT5659_IRQ_CTRL_2, 0x0040);
+		break;
+	case RT5659_JD_NULL:
+		break;
+	default:
+		dev_warn(&i2c->dev, "Currently, support JD3 only\n");
+		break;
+	}
+
+	INIT_DELAYED_WORK(&rt5659->jack_detect_work, rt5659_jack_detect_work);
+
+	if (rt5659->i2c->irq) {
+		ret = request_threaded_irq(rt5659->i2c->irq, NULL, rt5659_irq,
+			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+			| IRQF_ONESHOT, "rt5659", rt5659);
+		if (ret)
+			dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+
+	}
+
+	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659,
+			rt5659_dai, ARRAY_SIZE(rt5659_dai));
+
+	if (ret) {
+		if (rt5659->i2c->irq)
+			free_irq(rt5659->i2c->irq, rt5659);
+	}
+
+	return 0;
+}
+
+static int rt5659_i2c_remove(struct i2c_client *i2c)
+{
+	snd_soc_unregister_codec(&i2c->dev);
+
+	return 0;
+}
+
+void rt5659_i2c_shutdown(struct i2c_client *client)
+{
+	struct rt5659_priv *rt5659 = i2c_get_clientdata(client);
+
+	regmap_write(rt5659->regmap, RT5659_RESET, 0);
+}
+
+static const struct of_device_id rt5659_of_match[] = {
+	{ .compatible = "realtek,rt5658", },
+	{ .compatible = "realtek,rt5659", },
+	{},
+};
+
+static struct acpi_device_id rt5659_acpi_match[] = {
+		{ "10EC5658", 0},
+		{ "10EC5659", 0},
+		{ },
+};
+MODULE_DEVICE_TABLE(acpi, rt5659_acpi_match);
+
+struct i2c_driver rt5659_i2c_driver = {
+	.driver = {
+		.name = "rt5659",
+		.owner = THIS_MODULE,
+		.of_match_table = rt5659_of_match,
+		.acpi_match_table = ACPI_PTR(rt5659_acpi_match),
+	},
+	.probe = rt5659_i2c_probe,
+	.remove = rt5659_i2c_remove,
+	.shutdown = rt5659_i2c_shutdown,
+	.id_table = rt5659_i2c_id,
+};
+module_i2c_driver(rt5659_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5659 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5659.h b/sound/soc/codecs/rt5659.h
new file mode 100644
index 0000000..8f07ee9
--- /dev/null
+++ b/sound/soc/codecs/rt5659.h
@@ -0,0 +1,1819 @@
+/*
+ * rt5659.h  --  RT5659/RT5658 ALSA SoC audio driver
+ *
+ * Copyright 2015 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@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 __RT5659_H__
+#define __RT5659_H__
+
+#include <sound/rt5659.h>
+
+#define DEVICE_ID 0x6311
+
+/* Info */
+#define RT5659_RESET				0x0000
+#define RT5659_VENDOR_ID			0x00fd
+#define RT5659_VENDOR_ID_1			0x00fe
+#define RT5659_DEVICE_ID			0x00ff
+/*  I/O - Output */
+#define RT5659_SPO_VOL				0x0001
+#define RT5659_HP_VOL				0x0002
+#define RT5659_LOUT				0x0003
+#define RT5659_MONO_OUT				0x0004
+#define RT5659_HPL_GAIN				0x0005
+#define RT5659_HPR_GAIN				0x0006
+#define RT5659_MONO_GAIN			0x0007
+#define RT5659_SPDIF_CTRL_1			0x0008
+#define RT5659_SPDIF_CTRL_2			0x0009
+/* I/O - Input */
+#define RT5659_CAL_BST_CTRL			0x000a
+#define RT5659_IN1_IN2				0x000c
+#define RT5659_IN3_IN4				0x000d
+#define RT5659_INL1_INR1_VOL			0x000f
+/* I/O - Speaker */
+#define RT5659_EJD_CTRL_1			0x0010
+#define RT5659_EJD_CTRL_2			0x0011
+#define RT5659_EJD_CTRL_3			0x0012
+#define RT5659_SILENCE_CTRL			0x0015
+#define RT5659_PSV_CTRL				0x0016
+/* I/O - Sidetone */
+#define RT5659_SIDETONE_CTRL			0x0018
+/* I/O - ADC/DAC/DMIC */
+#define RT5659_DAC1_DIG_VOL			0x0019
+#define RT5659_DAC2_DIG_VOL			0x001a
+#define RT5659_DAC_CTRL				0x001b
+#define RT5659_STO1_ADC_DIG_VOL			0x001c
+#define RT5659_MONO_ADC_DIG_VOL			0x001d
+#define RT5659_STO2_ADC_DIG_VOL			0x001e
+#define RT5659_STO1_BOOST			0x001f
+#define RT5659_MONO_BOOST			0x0020
+#define RT5659_STO2_BOOST			0x0021
+#define RT5659_HP_IMP_GAIN_1			0x0022
+#define RT5659_HP_IMP_GAIN_2			0x0023
+/* Mixer - D-D */
+#define RT5659_STO1_ADC_MIXER			0x0026
+#define RT5659_MONO_ADC_MIXER			0x0027
+#define RT5659_AD_DA_MIXER			0x0029
+#define RT5659_STO_DAC_MIXER			0x002a
+#define RT5659_MONO_DAC_MIXER			0x002b
+#define RT5659_DIG_MIXER			0x002c
+#define RT5659_A_DAC_MUX			0x002d
+#define RT5659_DIG_INF23_DATA			0x002f
+/* Mixer - PDM */
+#define RT5659_PDM_OUT_CTRL			0x0031
+#define RT5659_PDM_DATA_CTRL_1			0x0032
+#define RT5659_PDM_DATA_CTRL_2			0x0033
+#define RT5659_PDM_DATA_CTRL_3			0x0034
+#define RT5659_PDM_DATA_CTRL_4			0x0035
+#define RT5659_SPDIF_CTRL			0x0036
+
+/* Mixer - ADC */
+#define RT5659_REC1_GAIN			0x003a
+#define RT5659_REC1_L1_MIXER			0x003b
+#define RT5659_REC1_L2_MIXER			0x003c
+#define RT5659_REC1_R1_MIXER			0x003d
+#define RT5659_REC1_R2_MIXER			0x003e
+#define RT5659_CAL_REC				0x0040
+#define RT5659_REC2_L1_MIXER			0x009b
+#define RT5659_REC2_L2_MIXER			0x009c
+#define RT5659_REC2_R1_MIXER			0x009d
+#define RT5659_REC2_R2_MIXER			0x009e
+#define RT5659_RC_CLK_CTRL			0x009f
+/* Mixer - DAC */
+#define RT5659_SPK_L_MIXER			0x0046
+#define RT5659_SPK_R_MIXER			0x0047
+#define RT5659_SPO_AMP_GAIN			0x0048
+#define RT5659_ALC_BACK_GAIN			0x0049
+#define RT5659_MONOMIX_GAIN			0x004a
+#define RT5659_MONOMIX_IN_GAIN			0x004b
+#define RT5659_OUT_L_GAIN			0x004d
+#define RT5659_OUT_L_MIXER			0x004e
+#define RT5659_OUT_R_GAIN			0x004f
+#define RT5659_OUT_R_MIXER			0x0050
+#define RT5659_LOUT_MIXER			0x0052
+
+#define RT5659_HAPTIC_GEN_CTRL_1		0x0053
+#define RT5659_HAPTIC_GEN_CTRL_2		0x0054
+#define RT5659_HAPTIC_GEN_CTRL_3		0x0055
+#define RT5659_HAPTIC_GEN_CTRL_4		0x0056
+#define RT5659_HAPTIC_GEN_CTRL_5		0x0057
+#define RT5659_HAPTIC_GEN_CTRL_6		0x0058
+#define RT5659_HAPTIC_GEN_CTRL_7		0x0059
+#define RT5659_HAPTIC_GEN_CTRL_8		0x005a
+#define RT5659_HAPTIC_GEN_CTRL_9		0x005b
+#define RT5659_HAPTIC_GEN_CTRL_10		0x005c
+#define RT5659_HAPTIC_GEN_CTRL_11		0x005d
+#define RT5659_HAPTIC_LPF_CTRL_1		0x005e
+#define RT5659_HAPTIC_LPF_CTRL_2		0x005f
+#define RT5659_HAPTIC_LPF_CTRL_3		0x0060
+/* Power */
+#define RT5659_PWR_DIG_1			0x0061
+#define RT5659_PWR_DIG_2			0x0062
+#define RT5659_PWR_ANLG_1			0x0063
+#define RT5659_PWR_ANLG_2			0x0064
+#define RT5659_PWR_ANLG_3			0x0065
+#define RT5659_PWR_MIXER			0x0066
+#define RT5659_PWR_VOL				0x0067
+/* Private Register Control */
+#define RT5659_PRIV_INDEX			0x006a
+#define RT5659_CLK_DET				0x006b
+#define RT5659_PRIV_DATA			0x006c
+/* System Clock Pre Divider Gating Control */
+#define RT5659_PRE_DIV_1			0x006e
+#define RT5659_PRE_DIV_2			0x006f
+/* Format - ADC/DAC */
+#define RT5659_I2S1_SDP				0x0070
+#define RT5659_I2S2_SDP				0x0071
+#define RT5659_I2S3_SDP				0x0072
+#define RT5659_ADDA_CLK_1			0x0073
+#define RT5659_ADDA_CLK_2			0x0074
+#define RT5659_DMIC_CTRL_1			0x0075
+#define RT5659_DMIC_CTRL_2			0x0076
+/* Format - TDM Control */
+#define RT5659_TDM_CTRL_1			0x0077
+#define RT5659_TDM_CTRL_2			0x0078
+#define RT5659_TDM_CTRL_3			0x0079
+#define RT5659_TDM_CTRL_4			0x007a
+#define RT5659_TDM_CTRL_5			0x007b
+
+/* Function - Analog */
+#define RT5659_GLB_CLK				0x0080
+#define RT5659_PLL_CTRL_1			0x0081
+#define RT5659_PLL_CTRL_2			0x0082
+#define RT5659_ASRC_1				0x0083
+#define RT5659_ASRC_2				0x0084
+#define RT5659_ASRC_3				0x0085
+#define RT5659_ASRC_4				0x0086
+#define RT5659_ASRC_5				0x0087
+#define RT5659_ASRC_6				0x0088
+#define RT5659_ASRC_7				0x0089
+#define RT5659_ASRC_8				0x008a
+#define RT5659_ASRC_9				0x008b
+#define RT5659_ASRC_10				0x008c
+#define RT5659_DEPOP_1				0x008e
+#define RT5659_DEPOP_2				0x008f
+#define RT5659_DEPOP_3				0x0090
+#define RT5659_HP_CHARGE_PUMP_1			0x0091
+#define RT5659_HP_CHARGE_PUMP_2			0x0092
+#define RT5659_MICBIAS_1			0x0093
+#define RT5659_MICBIAS_2			0x0094
+#define RT5659_ASRC_11				0x0097
+#define RT5659_ASRC_12				0x0098
+#define RT5659_ASRC_13				0x0099
+#define RT5659_REC_M1_M2_GAIN_CTRL		0x009a
+#define RT5659_CLASSD_CTRL_1			0x00a0
+#define RT5659_CLASSD_CTRL_2			0x00a1
+
+/* Function - Digital */
+#define RT5659_ADC_EQ_CTRL_1			0x00ae
+#define RT5659_ADC_EQ_CTRL_2			0x00af
+#define RT5659_DAC_EQ_CTRL_1			0x00b0
+#define RT5659_DAC_EQ_CTRL_2			0x00b1
+#define RT5659_DAC_EQ_CTRL_3			0x00b2
+
+#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_INT_ST_1				0x00be
+#define RT5659_INT_ST_2				0x00bf
+#define RT5659_GPIO_CTRL_1			0x00c0
+#define RT5659_GPIO_CTRL_2			0x00c1
+#define RT5659_GPIO_CTRL_3			0x00c2
+#define RT5659_GPIO_CTRL_4			0x00c3
+#define RT5659_GPIO_CTRL_5			0x00c4
+#define RT5659_GPIO_STA				0x00c5
+#define RT5659_SINE_GEN_CTRL_1			0x00cb
+#define RT5659_SINE_GEN_CTRL_2			0x00cc
+#define RT5659_SINE_GEN_CTRL_3			0x00cd
+#define RT5659_HP_AMP_DET_CTRL_1		0x00d6
+#define RT5659_HP_AMP_DET_CTRL_2		0x00d7
+#define RT5659_SV_ZCD_1				0x00d9
+#define RT5659_SV_ZCD_2				0x00da
+#define RT5659_IL_CMD_1				0x00db
+#define RT5659_IL_CMD_2				0x00dc
+#define RT5659_IL_CMD_3				0x00dd
+#define RT5659_IL_CMD_4				0x00de
+#define RT5659_4BTN_IL_CMD_1			0x00df
+#define RT5659_4BTN_IL_CMD_2			0x00e0
+#define RT5659_4BTN_IL_CMD_3			0x00e1
+#define RT5659_PSV_IL_CMD_1			0x00e4
+#define RT5659_PSV_IL_CMD_2			0x00e5
+
+#define RT5659_ADC_STO1_HP_CTRL_1		0x00ea
+#define RT5659_ADC_STO1_HP_CTRL_2		0x00eb
+#define RT5659_ADC_MONO_HP_CTRL_1		0x00ec
+#define RT5659_ADC_MONO_HP_CTRL_2		0x00ed
+#define RT5659_AJD1_CTRL			0x00f0
+#define RT5659_AJD2_AJD3_CTRL			0x00f1
+#define RT5659_JD1_THD				0x00f2
+#define RT5659_JD2_THD				0x00f3
+#define RT5659_JD3_THD				0x00f4
+#define RT5659_JD_CTRL_1			0x00f6
+#define RT5659_JD_CTRL_2			0x00f7
+#define RT5659_JD_CTRL_3			0x00f8
+#define RT5659_JD_CTRL_4			0x00f9
+/* General Control */
+#define RT5659_DIG_MISC				0x00fa
+#define RT5659_DUMMY_2				0x00fb
+#define RT5659_DUMMY_3				0x00fc
+
+#define RT5659_DAC_ADC_DIG_VOL			0x0100
+#define RT5659_BIAS_CUR_CTRL_1			0x010a
+#define RT5659_BIAS_CUR_CTRL_2			0x010b
+#define RT5659_BIAS_CUR_CTRL_3			0x010c
+#define RT5659_BIAS_CUR_CTRL_4			0x010d
+#define RT5659_BIAS_CUR_CTRL_5			0x010e
+#define RT5659_BIAS_CUR_CTRL_6			0x010f
+#define RT5659_BIAS_CUR_CTRL_7			0x0110
+#define RT5659_BIAS_CUR_CTRL_8			0x0111
+#define RT5659_BIAS_CUR_CTRL_9			0x0112
+#define RT5659_BIAS_CUR_CTRL_10			0x0113
+#define RT5659_MEMORY_TEST			0x0116
+#define RT5659_VREF_REC_OP_FB_CAP_CTRL		0x0117
+#define RT5659_CLASSD_0				0x011a
+#define RT5659_CLASSD_1				0x011b
+#define RT5659_CLASSD_2				0x011c
+#define RT5659_CLASSD_3				0x011d
+#define RT5659_CLASSD_4				0x011e
+#define RT5659_CLASSD_5				0x011f
+#define RT5659_CLASSD_6				0x0120
+#define RT5659_CLASSD_7				0x0121
+#define RT5659_CLASSD_8				0x0122
+#define RT5659_CLASSD_9				0x0123
+#define RT5659_CLASSD_10			0x0124
+#define RT5659_CHARGE_PUMP_1			0x0125
+#define RT5659_CHARGE_PUMP_2			0x0126
+#define RT5659_DIG_IN_CTRL_1			0x0132
+#define RT5659_DIG_IN_CTRL_2			0x0133
+#define RT5659_PAD_DRIVING_CTRL			0x0137
+#define RT5659_SOFT_RAMP_DEPOP			0x0138
+#define RT5659_PLL				0x0139
+#define RT5659_CHOP_DAC				0x013a
+#define RT5659_CHOP_ADC				0x013b
+#define RT5659_CALIB_ADC_CTRL			0x013c
+#define RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL	0x013e
+#define RT5659_VOL_TEST				0x013f
+#define RT5659_TEST_MODE_CTRL_1			0x0145
+#define RT5659_TEST_MODE_CTRL_2			0x0146
+#define RT5659_TEST_MODE_CTRL_3			0x0147
+#define RT5659_TEST_MODE_CTRL_4			0x0148
+#define RT5659_BASSBACK_CTRL			0x0150
+#define RT5659_MP3_PLUS_CTRL_1			0x0151
+#define RT5659_MP3_PLUS_CTRL_2			0x0152
+#define RT5659_MP3_HPF_A1			0x0153
+#define RT5659_MP3_HPF_A2			0x0154
+#define RT5659_MP3_HPF_H0			0x0155
+#define RT5659_MP3_LPF_H0			0x0156
+#define RT5659_3D_SPK_CTRL			0x0157
+#define RT5659_3D_SPK_COEF_1			0x0158
+#define RT5659_3D_SPK_COEF_2			0x0159
+#define RT5659_3D_SPK_COEF_3			0x015a
+#define RT5659_3D_SPK_COEF_4			0x015b
+#define RT5659_3D_SPK_COEF_5			0x015c
+#define RT5659_3D_SPK_COEF_6			0x015d
+#define RT5659_3D_SPK_COEF_7			0x015e
+#define RT5659_STO_NG2_CTRL_1			0x0160
+#define RT5659_STO_NG2_CTRL_2			0x0161
+#define RT5659_STO_NG2_CTRL_3			0x0162
+#define RT5659_STO_NG2_CTRL_4			0x0163
+#define RT5659_STO_NG2_CTRL_5			0x0164
+#define RT5659_STO_NG2_CTRL_6			0x0165
+#define RT5659_STO_NG2_CTRL_7			0x0166
+#define RT5659_STO_NG2_CTRL_8			0x0167
+#define RT5659_MONO_NG2_CTRL_1			0x0170
+#define RT5659_MONO_NG2_CTRL_2			0x0171
+#define RT5659_MONO_NG2_CTRL_3			0x0172
+#define RT5659_MONO_NG2_CTRL_4			0x0173
+#define RT5659_MONO_NG2_CTRL_5			0x0174
+#define RT5659_MONO_NG2_CTRL_6			0x0175
+#define RT5659_MID_HP_AMP_DET			0x0190
+#define RT5659_LOW_HP_AMP_DET			0x0191
+#define RT5659_LDO_CTRL				0x0192
+#define RT5659_HP_DECROSS_CTRL_1		0x01b0
+#define RT5659_HP_DECROSS_CTRL_2		0x01b1
+#define RT5659_HP_DECROSS_CTRL_3		0x01b2
+#define RT5659_HP_DECROSS_CTRL_4		0x01b3
+#define RT5659_HP_IMP_SENS_CTRL_1		0x01c0
+#define RT5659_HP_IMP_SENS_CTRL_2		0x01c1
+#define RT5659_HP_IMP_SENS_CTRL_3		0x01c2
+#define RT5659_HP_IMP_SENS_CTRL_4		0x01c3
+#define RT5659_HP_IMP_SENS_MAP_1		0x01c7
+#define RT5659_HP_IMP_SENS_MAP_2		0x01c8
+#define RT5659_HP_IMP_SENS_MAP_3		0x01c9
+#define RT5659_HP_IMP_SENS_MAP_4		0x01ca
+#define RT5659_HP_IMP_SENS_MAP_5		0x01cb
+#define RT5659_HP_IMP_SENS_MAP_6		0x01cc
+#define RT5659_HP_IMP_SENS_MAP_7		0x01cd
+#define RT5659_HP_IMP_SENS_MAP_8		0x01ce
+#define RT5659_HP_LOGIC_CTRL_1			0x01da
+#define RT5659_HP_LOGIC_CTRL_2			0x01db
+#define RT5659_HP_CALIB_CTRL_1			0x01de
+#define RT5659_HP_CALIB_CTRL_2			0x01df
+#define RT5659_HP_CALIB_CTRL_3			0x01e0
+#define RT5659_HP_CALIB_CTRL_4			0x01e1
+#define RT5659_HP_CALIB_CTRL_5			0x01e2
+#define RT5659_HP_CALIB_CTRL_6			0x01e3
+#define RT5659_HP_CALIB_CTRL_7			0x01e4
+#define RT5659_HP_CALIB_CTRL_9			0x01e6
+#define RT5659_HP_CALIB_CTRL_10			0x01e7
+#define RT5659_HP_CALIB_CTRL_11			0x01e8
+#define RT5659_HP_CALIB_STA_1			0x01ea
+#define RT5659_HP_CALIB_STA_2			0x01eb
+#define RT5659_HP_CALIB_STA_3			0x01ec
+#define RT5659_HP_CALIB_STA_4			0x01ed
+#define RT5659_HP_CALIB_STA_5			0x01ee
+#define RT5659_HP_CALIB_STA_6			0x01ef
+#define RT5659_HP_CALIB_STA_7			0x01f0
+#define RT5659_HP_CALIB_STA_8			0x01f1
+#define RT5659_HP_CALIB_STA_9			0x01f2
+#define RT5659_MONO_AMP_CALIB_CTRL_1		0x01f6
+#define RT5659_MONO_AMP_CALIB_CTRL_2		0x01f7
+#define RT5659_MONO_AMP_CALIB_CTRL_3		0x01f8
+#define RT5659_MONO_AMP_CALIB_CTRL_4		0x01f9
+#define RT5659_MONO_AMP_CALIB_CTRL_5		0x01fa
+#define RT5659_MONO_AMP_CALIB_STA_1		0x01fb
+#define RT5659_MONO_AMP_CALIB_STA_2		0x01fc
+#define RT5659_MONO_AMP_CALIB_STA_3		0x01fd
+#define RT5659_MONO_AMP_CALIB_STA_4		0x01fe
+#define RT5659_SPK_PWR_LMT_CTRL_1		0x0200
+#define RT5659_SPK_PWR_LMT_CTRL_2		0x0201
+#define RT5659_SPK_PWR_LMT_CTRL_3		0x0202
+#define RT5659_SPK_PWR_LMT_STA_1		0x0203
+#define RT5659_SPK_PWR_LMT_STA_2		0x0204
+#define RT5659_SPK_PWR_LMT_STA_3		0x0205
+#define RT5659_SPK_PWR_LMT_STA_4		0x0206
+#define RT5659_SPK_PWR_LMT_STA_5		0x0207
+#define RT5659_SPK_PWR_LMT_STA_6		0x0208
+#define RT5659_FLEX_SPK_BST_CTRL_1		0x0256
+#define RT5659_FLEX_SPK_BST_CTRL_2		0x0257
+#define RT5659_FLEX_SPK_BST_CTRL_3		0x0258
+#define RT5659_FLEX_SPK_BST_CTRL_4		0x0259
+#define RT5659_SPK_EX_LMT_CTRL_1		0x025a
+#define RT5659_SPK_EX_LMT_CTRL_2		0x025b
+#define RT5659_SPK_EX_LMT_CTRL_3		0x025c
+#define RT5659_SPK_EX_LMT_CTRL_4		0x025d
+#define RT5659_SPK_EX_LMT_CTRL_5		0x025e
+#define RT5659_SPK_EX_LMT_CTRL_6		0x025f
+#define RT5659_SPK_EX_LMT_CTRL_7		0x0260
+#define RT5659_ADJ_HPF_CTRL_1			0x0261
+#define RT5659_ADJ_HPF_CTRL_2			0x0262
+#define RT5659_SPK_DC_CAILB_CTRL_1		0x0265
+#define RT5659_SPK_DC_CAILB_CTRL_2		0x0266
+#define RT5659_SPK_DC_CAILB_CTRL_3		0x0267
+#define RT5659_SPK_DC_CAILB_CTRL_4		0x0268
+#define RT5659_SPK_DC_CAILB_CTRL_5		0x0269
+#define RT5659_SPK_DC_CAILB_STA_1		0x026a
+#define RT5659_SPK_DC_CAILB_STA_2		0x026b
+#define RT5659_SPK_DC_CAILB_STA_3		0x026c
+#define RT5659_SPK_DC_CAILB_STA_4		0x026d
+#define RT5659_SPK_DC_CAILB_STA_5		0x026e
+#define RT5659_SPK_DC_CAILB_STA_6		0x026f
+#define RT5659_SPK_DC_CAILB_STA_7		0x0270
+#define RT5659_SPK_DC_CAILB_STA_8		0x0271
+#define RT5659_SPK_DC_CAILB_STA_9		0x0272
+#define RT5659_SPK_DC_CAILB_STA_10		0x0273
+#define RT5659_SPK_VDD_STA_1			0x0280
+#define RT5659_SPK_VDD_STA_2			0x0281
+#define RT5659_SPK_DC_DET_CTRL_1		0x0282
+#define RT5659_SPK_DC_DET_CTRL_2		0x0283
+#define RT5659_SPK_DC_DET_CTRL_3		0x0284
+#define RT5659_PURE_DC_DET_CTRL_1		0x0290
+#define RT5659_PURE_DC_DET_CTRL_2		0x0291
+#define RT5659_DUMMY_4				0x02fa
+#define RT5659_DUMMY_5				0x02fb
+#define RT5659_DUMMY_6				0x02fc
+#define RT5659_DRC1_CTRL_1			0x0300
+#define RT5659_DRC1_CTRL_2			0x0301
+#define RT5659_DRC1_CTRL_3			0x0302
+#define RT5659_DRC1_CTRL_4			0x0303
+#define RT5659_DRC1_CTRL_5			0x0304
+#define RT5659_DRC1_CTRL_6			0x0305
+#define RT5659_DRC1_HARD_LMT_CTRL_1		0x0306
+#define RT5659_DRC1_HARD_LMT_CTRL_2		0x0307
+#define RT5659_DRC2_CTRL_1			0x0308
+#define RT5659_DRC2_CTRL_2			0x0309
+#define RT5659_DRC2_CTRL_3			0x030a
+#define RT5659_DRC2_CTRL_4			0x030b
+#define RT5659_DRC2_CTRL_5			0x030c
+#define RT5659_DRC2_CTRL_6			0x030d
+#define RT5659_DRC2_HARD_LMT_CTRL_1		0x030e
+#define RT5659_DRC2_HARD_LMT_CTRL_2		0x030f
+#define RT5659_DRC1_PRIV_1			0x0310
+#define RT5659_DRC1_PRIV_2			0x0311
+#define RT5659_DRC1_PRIV_3			0x0312
+#define RT5659_DRC1_PRIV_4			0x0313
+#define RT5659_DRC1_PRIV_5			0x0314
+#define RT5659_DRC1_PRIV_6			0x0315
+#define RT5659_DRC1_PRIV_7			0x0316
+#define RT5659_DRC2_PRIV_1			0x0317
+#define RT5659_DRC2_PRIV_2			0x0318
+#define RT5659_DRC2_PRIV_3			0x0319
+#define RT5659_DRC2_PRIV_4			0x031a
+#define RT5659_DRC2_PRIV_5			0x031b
+#define RT5659_DRC2_PRIV_6			0x031c
+#define RT5659_DRC2_PRIV_7			0x031d
+#define RT5659_MULTI_DRC_CTRL			0x0320
+#define RT5659_CROSS_OVER_1			0x0321
+#define RT5659_CROSS_OVER_2			0x0322
+#define RT5659_CROSS_OVER_3			0x0323
+#define RT5659_CROSS_OVER_4			0x0324
+#define RT5659_CROSS_OVER_5			0x0325
+#define RT5659_CROSS_OVER_6			0x0326
+#define RT5659_CROSS_OVER_7			0x0327
+#define RT5659_CROSS_OVER_8			0x0328
+#define RT5659_CROSS_OVER_9			0x0329
+#define RT5659_CROSS_OVER_10			0x032a
+#define RT5659_ALC_PGA_CTRL_1			0x0330
+#define RT5659_ALC_PGA_CTRL_2			0x0331
+#define RT5659_ALC_PGA_CTRL_3			0x0332
+#define RT5659_ALC_PGA_CTRL_4			0x0333
+#define RT5659_ALC_PGA_CTRL_5			0x0334
+#define RT5659_ALC_PGA_CTRL_6			0x0335
+#define RT5659_ALC_PGA_CTRL_7			0x0336
+#define RT5659_ALC_PGA_CTRL_8			0x0337
+#define RT5659_ALC_PGA_STA_1			0x0338
+#define RT5659_ALC_PGA_STA_2			0x0339
+#define RT5659_ALC_PGA_STA_3			0x033a
+#define RT5659_DAC_L_EQ_PRE_VOL			0x0340
+#define RT5659_DAC_R_EQ_PRE_VOL			0x0341
+#define RT5659_DAC_L_EQ_POST_VOL		0x0342
+#define RT5659_DAC_R_EQ_POST_VOL		0x0343
+#define RT5659_DAC_L_EQ_LPF1_A1			0x0344
+#define RT5659_DAC_L_EQ_LPF1_H0			0x0345
+#define RT5659_DAC_R_EQ_LPF1_A1			0x0346
+#define RT5659_DAC_R_EQ_LPF1_H0			0x0347
+#define RT5659_DAC_L_EQ_BPF2_A1			0x0348
+#define RT5659_DAC_L_EQ_BPF2_A2			0x0349
+#define RT5659_DAC_L_EQ_BPF2_H0			0x034a
+#define RT5659_DAC_R_EQ_BPF2_A1			0x034b
+#define RT5659_DAC_R_EQ_BPF2_A2			0x034c
+#define RT5659_DAC_R_EQ_BPF2_H0			0x034d
+#define RT5659_DAC_L_EQ_BPF3_A1			0x034e
+#define RT5659_DAC_L_EQ_BPF3_A2			0x034f
+#define RT5659_DAC_L_EQ_BPF3_H0			0x0350
+#define RT5659_DAC_R_EQ_BPF3_A1			0x0351
+#define RT5659_DAC_R_EQ_BPF3_A2			0x0352
+#define RT5659_DAC_R_EQ_BPF3_H0			0x0353
+#define RT5659_DAC_L_EQ_BPF4_A1			0x0354
+#define RT5659_DAC_L_EQ_BPF4_A2			0x0355
+#define RT5659_DAC_L_EQ_BPF4_H0			0x0356
+#define RT5659_DAC_R_EQ_BPF4_A1			0x0357
+#define RT5659_DAC_R_EQ_BPF4_A2			0x0358
+#define RT5659_DAC_R_EQ_BPF4_H0			0x0359
+#define RT5659_DAC_L_EQ_HPF1_A1			0x035a
+#define RT5659_DAC_L_EQ_HPF1_H0			0x035b
+#define RT5659_DAC_R_EQ_HPF1_A1			0x035c
+#define RT5659_DAC_R_EQ_HPF1_H0			0x035d
+#define RT5659_DAC_L_EQ_HPF2_A1			0x035e
+#define RT5659_DAC_L_EQ_HPF2_A2			0x035f
+#define RT5659_DAC_L_EQ_HPF2_H0			0x0360
+#define RT5659_DAC_R_EQ_HPF2_A1			0x0361
+#define RT5659_DAC_R_EQ_HPF2_A2			0x0362
+#define RT5659_DAC_R_EQ_HPF2_H0			0x0363
+#define RT5659_DAC_L_BI_EQ_BPF1_H0_1		0x0364
+#define RT5659_DAC_L_BI_EQ_BPF1_H0_2		0x0365
+#define RT5659_DAC_L_BI_EQ_BPF1_B1_1		0x0366
+#define RT5659_DAC_L_BI_EQ_BPF1_B1_2		0x0367
+#define RT5659_DAC_L_BI_EQ_BPF1_B2_1		0x0368
+#define RT5659_DAC_L_BI_EQ_BPF1_B2_2		0x0369
+#define RT5659_DAC_L_BI_EQ_BPF1_A1_1		0x036a
+#define RT5659_DAC_L_BI_EQ_BPF1_A1_2		0x036b
+#define RT5659_DAC_L_BI_EQ_BPF1_A2_1		0x036c
+#define RT5659_DAC_L_BI_EQ_BPF1_A2_2		0x036d
+#define RT5659_DAC_R_BI_EQ_BPF1_H0_1		0x036e
+#define RT5659_DAC_R_BI_EQ_BPF1_H0_2		0x036f
+#define RT5659_DAC_R_BI_EQ_BPF1_B1_1		0x0370
+#define RT5659_DAC_R_BI_EQ_BPF1_B1_2		0x0371
+#define RT5659_DAC_R_BI_EQ_BPF1_B2_1		0x0372
+#define RT5659_DAC_R_BI_EQ_BPF1_B2_2		0x0373
+#define RT5659_DAC_R_BI_EQ_BPF1_A1_1		0x0374
+#define RT5659_DAC_R_BI_EQ_BPF1_A1_2		0x0375
+#define RT5659_DAC_R_BI_EQ_BPF1_A2_1		0x0376
+#define RT5659_DAC_R_BI_EQ_BPF1_A2_2		0x0377
+#define RT5659_ADC_L_EQ_LPF1_A1			0x03d0
+#define RT5659_ADC_R_EQ_LPF1_A1			0x03d1
+#define RT5659_ADC_L_EQ_LPF1_H0			0x03d2
+#define RT5659_ADC_R_EQ_LPF1_H0			0x03d3
+#define RT5659_ADC_L_EQ_BPF1_A1			0x03d4
+#define RT5659_ADC_R_EQ_BPF1_A1			0x03d5
+#define RT5659_ADC_L_EQ_BPF1_A2			0x03d6
+#define RT5659_ADC_R_EQ_BPF1_A2			0x03d7
+#define RT5659_ADC_L_EQ_BPF1_H0			0x03d8
+#define RT5659_ADC_R_EQ_BPF1_H0			0x03d9
+#define RT5659_ADC_L_EQ_BPF2_A1			0x03da
+#define RT5659_ADC_R_EQ_BPF2_A1			0x03db
+#define RT5659_ADC_L_EQ_BPF2_A2			0x03dc
+#define RT5659_ADC_R_EQ_BPF2_A2			0x03dd
+#define RT5659_ADC_L_EQ_BPF2_H0			0x03de
+#define RT5659_ADC_R_EQ_BPF2_H0			0x03df
+#define RT5659_ADC_L_EQ_BPF3_A1			0x03e0
+#define RT5659_ADC_R_EQ_BPF3_A1			0x03e1
+#define RT5659_ADC_L_EQ_BPF3_A2			0x03e2
+#define RT5659_ADC_R_EQ_BPF3_A2			0x03e3
+#define RT5659_ADC_L_EQ_BPF3_H0			0x03e4
+#define RT5659_ADC_R_EQ_BPF3_H0			0x03e5
+#define RT5659_ADC_L_EQ_BPF4_A1			0x03e6
+#define RT5659_ADC_R_EQ_BPF4_A1			0x03e7
+#define RT5659_ADC_L_EQ_BPF4_A2			0x03e8
+#define RT5659_ADC_R_EQ_BPF4_A2			0x03e9
+#define RT5659_ADC_L_EQ_BPF4_H0			0x03ea
+#define RT5659_ADC_R_EQ_BPF4_H0			0x03eb
+#define RT5659_ADC_L_EQ_HPF1_A1			0x03ec
+#define RT5659_ADC_R_EQ_HPF1_A1			0x03ed
+#define RT5659_ADC_L_EQ_HPF1_H0			0x03ee
+#define RT5659_ADC_R_EQ_HPF1_H0			0x03ef
+#define RT5659_ADC_L_EQ_PRE_VOL			0x03f0
+#define RT5659_ADC_R_EQ_PRE_VOL			0x03f1
+#define RT5659_ADC_L_EQ_POST_VOL		0x03f2
+#define RT5659_ADC_R_EQ_POST_VOL		0x03f3
+
+
+
+/* global definition */
+#define RT5659_L_MUTE				(0x1 << 15)
+#define RT5659_L_MUTE_SFT			15
+#define RT5659_VOL_L_MUTE			(0x1 << 14)
+#define RT5659_VOL_L_SFT			14
+#define RT5659_R_MUTE				(0x1 << 7)
+#define RT5659_R_MUTE_SFT			7
+#define RT5659_VOL_R_MUTE			(0x1 << 6)
+#define RT5659_VOL_R_SFT			6
+#define RT5659_L_VOL_MASK			(0x3f << 8)
+#define RT5659_L_VOL_SFT			8
+#define RT5659_R_VOL_MASK			(0x3f)
+#define RT5659_R_VOL_SFT			0
+
+/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/
+#define RT5659_G_HP				(0x1f << 8)
+#define RT5659_G_HP_SFT				8
+#define RT5659_G_STO_DA_DMIX			(0x1f)
+#define RT5659_G_STO_DA_SFT			0
+
+/* IN1/IN2 Control (0x000c) */
+#define RT5659_IN1_DF_MASK			(0x1 << 15)
+#define RT5659_IN1_DF				15
+#define RT5659_BST1_MASK			(0x7f << 8)
+#define RT5659_BST1_SFT				8
+#define RT5659_BST2_MASK			(0x7f)
+#define RT5659_BST2_SFT				0
+
+/* IN3/IN4 Control (0x000d) */
+#define RT5659_IN3_DF_MASK			(0x1 << 15)
+#define RT5659_IN3_DF				15
+#define RT5659_BST3_MASK			(0x7f << 8)
+#define RT5659_BST3_SFT				8
+#define RT5659_IN4_DF_MASK			(0x1 << 7)
+#define RT5659_IN4_DF				7
+#define RT5659_BST4_MASK			(0x7f)
+#define RT5659_BST4_SFT				0
+
+/* INL and INR Volume Control (0x000f) */
+#define RT5659_INL_VOL_MASK			(0x1f << 8)
+#define RT5659_INL_VOL_SFT			8
+#define RT5659_INR_VOL_MASK			(0x1f)
+#define RT5659_INR_VOL_SFT			0
+
+/* Embeeded Jack and Type Detection Control 1 (0x0010) */
+#define RT5659_EMB_JD_EN			(0x1 << 15)
+#define RT5659_EMB_JD_EN_SFT			15
+#define RT5659_JD_MODE				(0x1 << 13)
+#define RT5659_JD_MODE_SFT			13
+#define RT5659_EXT_JD_EN			(0x1 << 11)
+#define RT5659_EXT_JD_EN_SFT			11
+#define RT5659_EXT_JD_DIG			(0x1 << 9)
+
+/* Embeeded Jack and Type Detection Control 2 (0x0011) */
+#define RT5659_EXT_JD_SRC			(0x7 << 4)
+#define RT5659_EXT_JD_SRC_SFT			4
+#define RT5659_EXT_JD_SRC_GPIO_JD1		(0x0 << 4)
+#define RT5659_EXT_JD_SRC_GPIO_JD2		(0x1 << 4)
+#define RT5659_EXT_JD_SRC_JD1_1			(0x2 << 4)
+#define RT5659_EXT_JD_SRC_JD1_2			(0x3 << 4)
+#define RT5659_EXT_JD_SRC_JD2			(0x4 << 4)
+#define RT5659_EXT_JD_SRC_JD3			(0x5 << 4)
+#define RT5659_EXT_JD_SRC_MANUAL		(0x6 << 4)
+
+/* Slience Detection Control (0x0015) */
+#define RT5659_SIL_DET_MASK			(0x1 << 15)
+#define RT5659_SIL_DET_DIS			(0x0 << 15)
+#define RT5659_SIL_DET_EN			(0x1 << 15)
+
+/* Sidetone Control (0x0018) */
+#define RT5659_ST_SEL_MASK			(0x7 << 9)
+#define RT5659_ST_SEL_SFT			9
+#define RT5659_ST_EN				(0x1 << 6)
+#define RT5659_ST_EN_SFT			6
+
+/* DAC1 Digital Volume (0x0019) */
+#define RT5659_DAC_L1_VOL_MASK			(0xff << 8)
+#define RT5659_DAC_L1_VOL_SFT			8
+#define RT5659_DAC_R1_VOL_MASK			(0xff)
+#define RT5659_DAC_R1_VOL_SFT			0
+
+/* DAC2 Digital Volume (0x001a) */
+#define RT5659_DAC_L2_VOL_MASK			(0xff << 8)
+#define RT5659_DAC_L2_VOL_SFT			8
+#define RT5659_DAC_R2_VOL_MASK			(0xff)
+#define RT5659_DAC_R2_VOL_SFT			0
+
+/* DAC2 Control (0x001b) */
+#define RT5659_M_DAC2_L_VOL			(0x1 << 13)
+#define RT5659_M_DAC2_L_VOL_SFT			13
+#define RT5659_M_DAC2_R_VOL			(0x1 << 12)
+#define RT5659_M_DAC2_R_VOL_SFT			12
+#define RT5659_DAC_L2_SEL_MASK			(0x7 << 4)
+#define RT5659_DAC_L2_SEL_SFT			4
+#define RT5659_DAC_R2_SEL_MASK			(0x7 << 0)
+#define RT5659_DAC_R2_SEL_SFT			0
+
+/* ADC Digital Volume Control (0x001c) */
+#define RT5659_ADC_L_VOL_MASK			(0x7f << 8)
+#define RT5659_ADC_L_VOL_SFT			8
+#define RT5659_ADC_R_VOL_MASK			(0x7f)
+#define RT5659_ADC_R_VOL_SFT			0
+
+/* Mono ADC Digital Volume Control (0x001d) */
+#define RT5659_MONO_ADC_L_VOL_MASK		(0x7f << 8)
+#define RT5659_MONO_ADC_L_VOL_SFT		8
+#define RT5659_MONO_ADC_R_VOL_MASK		(0x7f)
+#define RT5659_MONO_ADC_R_VOL_SFT		0
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5659_STO1_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5659_STO1_ADC_L_BST_SFT		14
+#define RT5659_STO1_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5659_STO1_ADC_R_BST_SFT		12
+
+/* Mono ADC Boost Gain Control (0x0020) */
+#define RT5659_MONO_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5659_MONO_ADC_L_BST_SFT		14
+#define RT5659_MONO_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5659_MONO_ADC_R_BST_SFT		12
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5659_STO2_ADC_L_BST_MASK		(0x3 << 14)
+#define RT5659_STO2_ADC_L_BST_SFT		14
+#define RT5659_STO2_ADC_R_BST_MASK		(0x3 << 12)
+#define RT5659_STO2_ADC_R_BST_SFT		12
+
+/* Stereo ADC Mixer Control (0x0026) */
+#define RT5659_M_STO1_ADC_L1			(0x1 << 15)
+#define RT5659_M_STO1_ADC_L1_SFT		15
+#define RT5659_M_STO1_ADC_L2			(0x1 << 14)
+#define RT5659_M_STO1_ADC_L2_SFT		14
+#define RT5659_STO1_ADC1_SRC_MASK		(0x1 << 13)
+#define RT5659_STO1_ADC1_SRC_SFT		13
+#define RT5659_STO1_ADC1_SRC_ADC		(0x1 << 13)
+#define RT5659_STO1_ADC1_SRC_DACMIX		(0x0 << 13)
+#define RT5659_STO1_ADC_SRC_MASK		(0x1 << 12)
+#define RT5659_STO1_ADC_SRC_SFT			12
+#define RT5659_STO1_ADC_SRC_ADC1		(0x1 << 12)
+#define RT5659_STO1_ADC_SRC_ADC2		(0x0 << 12)
+#define RT5659_STO1_ADC2_SRC_MASK		(0x1 << 11)
+#define RT5659_STO1_ADC2_SRC_SFT		11
+#define RT5659_STO1_DMIC_SRC_MASK		(0x1 << 8)
+#define RT5659_STO1_DMIC_SRC_SFT		8
+#define RT5659_STO1_DMIC_SRC_DMIC2		(0x1 << 8)
+#define RT5659_STO1_DMIC_SRC_DMIC1		(0x0 << 8)
+#define RT5659_M_STO1_ADC_R1			(0x1 << 6)
+#define RT5659_M_STO1_ADC_R1_SFT		6
+#define RT5659_M_STO1_ADC_R2			(0x1 << 5)
+#define RT5659_M_STO1_ADC_R2_SFT		5
+
+/* Mono1 ADC Mixer control (0x0027) */
+#define RT5659_M_MONO_ADC_L1			(0x1 << 15)
+#define RT5659_M_MONO_ADC_L1_SFT		15
+#define RT5659_M_MONO_ADC_L2			(0x1 << 14)
+#define RT5659_M_MONO_ADC_L2_SFT		14
+#define RT5659_MONO_ADC_L2_SRC_MASK		(0x1 << 12)
+#define RT5659_MONO_ADC_L2_SRC_SFT		12
+#define RT5659_MONO_ADC_L1_SRC_MASK		(0x1 << 11)
+#define RT5659_MONO_ADC_L1_SRC_SFT		11
+#define RT5659_MONO_ADC_L_SRC_MASK		(0x3 << 9)
+#define RT5659_MONO_ADC_L_SRC_SFT		9
+#define RT5659_MONO_DMIC_L_SRC_MASK		(0x1 << 8)
+#define RT5659_MONO_DMIC_L_SRC_SFT		8
+#define RT5659_M_MONO_ADC_R1			(0x1 << 7)
+#define RT5659_M_MONO_ADC_R1_SFT		7
+#define RT5659_M_MONO_ADC_R2			(0x1 << 6)
+#define RT5659_M_MONO_ADC_R2_SFT		6
+#define RT5659_STO2_ADC_SRC_MASK		(0x1 << 5)
+#define RT5659_STO2_ADC_SRC_SFT			5
+#define RT5659_MONO_ADC_R2_SRC_MASK		(0x1 << 4)
+#define RT5659_MONO_ADC_R2_SRC_SFT		4
+#define RT5659_MONO_ADC_R1_SRC_MASK		(0x1 << 3)
+#define RT5659_MONO_ADC_R1_SRC_SFT		3
+#define RT5659_MONO_ADC_R_SRC_MASK		(0x3 << 1)
+#define RT5659_MONO_ADC_R_SRC_SFT		1
+#define RT5659_MONO_DMIC_R_SRC_MASK		0x1
+#define RT5659_MONO_DMIC_R_SRC_SFT		0
+
+/* ADC Mixer to DAC Mixer Control (0x0029) */
+#define RT5659_M_ADCMIX_L			(0x1 << 15)
+#define RT5659_M_ADCMIX_L_SFT			15
+#define RT5659_M_DAC1_L				(0x1 << 14)
+#define RT5659_M_DAC1_L_SFT			14
+#define RT5659_DAC1_R_SEL_MASK			(0x3 << 10)
+#define RT5659_DAC1_R_SEL_SFT			10
+#define RT5659_DAC1_R_SEL_IF1			(0x0 << 10)
+#define RT5659_DAC1_R_SEL_IF2			(0x1 << 10)
+#define RT5659_DAC1_R_SEL_IF3			(0x2 << 10)
+#define RT5659_DAC1_L_SEL_MASK			(0x3 << 8)
+#define RT5659_DAC1_L_SEL_SFT			8
+#define RT5659_DAC1_L_SEL_IF1			(0x0 << 8)
+#define RT5659_DAC1_L_SEL_IF2			(0x1 << 8)
+#define RT5659_DAC1_L_SEL_IF3			(0x2 << 8)
+#define RT5659_M_ADCMIX_R			(0x1 << 7)
+#define RT5659_M_ADCMIX_R_SFT			7
+#define RT5659_M_DAC1_R				(0x1 << 6)
+#define RT5659_M_DAC1_R_SFT			6
+
+/* Stereo DAC Mixer Control (0x002a) */
+#define RT5659_M_DAC_L1_STO_L			(0x1 << 15)
+#define RT5659_M_DAC_L1_STO_L_SFT		15
+#define RT5659_G_DAC_L1_STO_L_MASK		(0x1 << 14)
+#define RT5659_G_DAC_L1_STO_L_SFT		14
+#define RT5659_M_DAC_R1_STO_L			(0x1 << 13)
+#define RT5659_M_DAC_R1_STO_L_SFT		13
+#define RT5659_G_DAC_R1_STO_L_MASK		(0x1 << 12)
+#define RT5659_G_DAC_R1_STO_L_SFT		12
+#define RT5659_M_DAC_L2_STO_L			(0x1 << 11)
+#define RT5659_M_DAC_L2_STO_L_SFT		11
+#define RT5659_G_DAC_L2_STO_L_MASK		(0x1 << 10)
+#define RT5659_G_DAC_L2_STO_L_SFT		10
+#define RT5659_M_DAC_R2_STO_L			(0x1 << 9)
+#define RT5659_M_DAC_R2_STO_L_SFT		9
+#define RT5659_G_DAC_R2_STO_L_MASK		(0x1 << 8)
+#define RT5659_G_DAC_R2_STO_L_SFT		8
+#define RT5659_M_DAC_L1_STO_R			(0x1 << 7)
+#define RT5659_M_DAC_L1_STO_R_SFT		7
+#define RT5659_G_DAC_L1_STO_R_MASK		(0x1 << 6)
+#define RT5659_G_DAC_L1_STO_R_SFT		6
+#define RT5659_M_DAC_R1_STO_R			(0x1 << 5)
+#define RT5659_M_DAC_R1_STO_R_SFT		5
+#define RT5659_G_DAC_R1_STO_R_MASK		(0x1 << 4)
+#define RT5659_G_DAC_R1_STO_R_SFT		4
+#define RT5659_M_DAC_L2_STO_R			(0x1 << 3)
+#define RT5659_M_DAC_L2_STO_R_SFT		3
+#define RT5659_G_DAC_L2_STO_R_MASK		(0x1 << 2)
+#define RT5659_G_DAC_L2_STO_R_SFT		2
+#define RT5659_M_DAC_R2_STO_R			(0x1 << 1)
+#define RT5659_M_DAC_R2_STO_R_SFT		1
+#define RT5659_G_DAC_R2_STO_R_MASK		(0x1)
+#define RT5659_G_DAC_R2_STO_R_SFT		0
+
+/* Mono DAC Mixer Control (0x002b) */
+#define RT5659_M_DAC_L1_MONO_L			(0x1 << 15)
+#define RT5659_M_DAC_L1_MONO_L_SFT		15
+#define RT5659_G_DAC_L1_MONO_L_MASK		(0x1 << 14)
+#define RT5659_G_DAC_L1_MONO_L_SFT		14
+#define RT5659_M_DAC_R1_MONO_L			(0x1 << 13)
+#define RT5659_M_DAC_R1_MONO_L_SFT		13
+#define RT5659_G_DAC_R1_MONO_L_MASK		(0x1 << 12)
+#define RT5659_G_DAC_R1_MONO_L_SFT		12
+#define RT5659_M_DAC_L2_MONO_L			(0x1 << 11)
+#define RT5659_M_DAC_L2_MONO_L_SFT		11
+#define RT5659_G_DAC_L2_MONO_L_MASK		(0x1 << 10)
+#define RT5659_G_DAC_L2_MONO_L_SFT		10
+#define RT5659_M_DAC_R2_MONO_L			(0x1 << 9)
+#define RT5659_M_DAC_R2_MONO_L_SFT		9
+#define RT5659_G_DAC_R2_MONO_L_MASK		(0x1 << 8)
+#define RT5659_G_DAC_R2_MONO_L_SFT		8
+#define RT5659_M_DAC_L1_MONO_R			(0x1 << 7)
+#define RT5659_M_DAC_L1_MONO_R_SFT		7
+#define RT5659_G_DAC_L1_MONO_R_MASK		(0x1 << 6)
+#define RT5659_G_DAC_L1_MONO_R_SFT		6
+#define RT5659_M_DAC_R1_MONO_R			(0x1 << 5)
+#define RT5659_M_DAC_R1_MONO_R_SFT		5
+#define RT5659_G_DAC_R1_MONO_R_MASK		(0x1 << 4)
+#define RT5659_G_DAC_R1_MONO_R_SFT		4
+#define RT5659_M_DAC_L2_MONO_R			(0x1 << 3)
+#define RT5659_M_DAC_L2_MONO_R_SFT		3
+#define RT5659_G_DAC_L2_MONO_R_MASK		(0x1 << 2)
+#define RT5659_G_DAC_L2_MONO_R_SFT		2
+#define RT5659_M_DAC_R2_MONO_R			(0x1 << 1)
+#define RT5659_M_DAC_R2_MONO_R_SFT		1
+#define RT5659_G_DAC_R2_MONO_R_MASK		(0x1)
+#define RT5659_G_DAC_R2_MONO_R_SFT		0
+
+/* Digital Mixer Control (0x002c) */
+#define RT5659_M_DAC_MIX_L			(0x1 << 7)
+#define RT5659_M_DAC_MIX_L_SFT			7
+#define RT5659_DAC_MIX_L_MASK			(0x1 << 6)
+#define RT5659_DAC_MIX_L_SFT			6
+#define RT5659_M_DAC_MIX_R			(0x1 << 5)
+#define RT5659_M_DAC_MIX_R_SFT			5
+#define RT5659_DAC_MIX_R_MASK			(0x1 << 4)
+#define RT5659_DAC_MIX_R_SFT			4
+
+/* Analog DAC Input Source Control (0x002d) */
+#define RT5659_A_DACL1_SEL			(0x1 << 3)
+#define RT5659_A_DACL1_SFT			3
+#define RT5659_A_DACR1_SEL			(0x1 << 2)
+#define RT5659_A_DACR1_SFT			2
+#define RT5659_A_DACL2_SEL			(0x1 << 1)
+#define RT5659_A_DACL2_SFT			1
+#define RT5659_A_DACR2_SEL			(0x1 << 0)
+#define RT5659_A_DACR2_SFT			0
+
+/* Digital Interface Data Control (0x002f) */
+#define RT5659_IF2_ADC3_IN_MASK			(0x3 << 14)
+#define RT5659_IF2_ADC3_IN_SFT			14
+#define RT5659_IF2_ADC_IN_MASK			(0x3 << 12)
+#define RT5659_IF2_ADC_IN_SFT			12
+#define RT5659_IF2_DAC_SEL_MASK			(0x3 << 10)
+#define RT5659_IF2_DAC_SEL_SFT			10
+#define RT5659_IF2_ADC_SEL_MASK			(0x3 << 8)
+#define RT5659_IF2_ADC_SEL_SFT			8
+#define RT5659_IF3_DAC_SEL_MASK			(0x3 << 6)
+#define RT5659_IF3_DAC_SEL_SFT			6
+#define RT5659_IF3_ADC_SEL_MASK			(0x3 << 4)
+#define RT5659_IF3_ADC_SEL_SFT			4
+#define RT5659_IF3_ADC_IN_MASK			(0x3 << 0)
+#define RT5659_IF3_ADC_IN_SFT			0
+
+/* PDM Output Control (0x0031) */
+#define RT5659_PDM1_L_MASK			(0x1 << 15)
+#define RT5659_PDM1_L_SFT			15
+#define RT5659_M_PDM1_L				(0x1 << 14)
+#define RT5659_M_PDM1_L_SFT			14
+#define RT5659_PDM1_R_MASK			(0x1 << 13)
+#define RT5659_PDM1_R_SFT			13
+#define RT5659_M_PDM1_R				(0x1 << 12)
+#define RT5659_M_PDM1_R_SFT			12
+#define RT5659_PDM2_BUSY			(0x1 << 7)
+#define RT5659_PDM1_BUSY			(0x1 << 6)
+#define RT5659_PDM_PATTERN			(0x1 << 5)
+#define RT5659_PDM_GAIN				(0x1 << 4)
+#define RT5659_PDM_DIV_MASK			(0x3)
+
+/*S/PDIF Output Control (0x0036) */
+#define RT5659_SPDIF_SEL_MASK			(0x3 << 0)
+#define RT5659_SPDIF_SEL_SFT			0
+
+/* REC Left Mixer Control 2 (0x003c) */
+#define RT5659_M_BST1_RM1_L			(0x1 << 5)
+#define RT5659_M_BST1_RM1_L_SFT			5
+#define RT5659_M_BST2_RM1_L			(0x1 << 4)
+#define RT5659_M_BST2_RM1_L_SFT			4
+#define RT5659_M_BST3_RM1_L			(0x1 << 3)
+#define RT5659_M_BST3_RM1_L_SFT			3
+#define RT5659_M_BST4_RM1_L			(0x1 << 2)
+#define RT5659_M_BST4_RM1_L_SFT			2
+#define RT5659_M_INL_RM1_L			(0x1 << 1)
+#define RT5659_M_INL_RM1_L_SFT			1
+#define RT5659_M_SPKVOLL_RM1_L			(0x1)
+#define RT5659_M_SPKVOLL_RM1_L_SFT		0
+
+/* REC Right Mixer Control 2 (0x003e) */
+#define RT5659_M_BST1_RM1_R			(0x1 << 5)
+#define RT5659_M_BST1_RM1_R_SFT			5
+#define RT5659_M_BST2_RM1_R			(0x1 << 4)
+#define RT5659_M_BST2_RM1_R_SFT			4
+#define RT5659_M_BST3_RM1_R			(0x1 << 3)
+#define RT5659_M_BST3_RM1_R_SFT			3
+#define RT5659_M_BST4_RM1_R			(0x1 << 2)
+#define RT5659_M_BST4_RM1_R_SFT			2
+#define RT5659_M_INR_RM1_R			(0x1 << 1)
+#define RT5659_M_INR_RM1_R_SFT			1
+#define RT5659_M_HPOVOLR_RM1_R			(0x1)
+#define RT5659_M_HPOVOLR_RM1_R_SFT		0
+
+/* SPK Left Mixer Control (0x0046) */
+#define RT5659_M_BST3_SM_L			(0x1 << 4)
+#define RT5659_M_BST3_SM_L_SFT			4
+#define RT5659_M_IN_R_SM_L			(0x1 << 3)
+#define RT5659_M_IN_R_SM_L_SFT			3
+#define RT5659_M_IN_L_SM_L			(0x1 << 2)
+#define RT5659_M_IN_L_SM_L_SFT			2
+#define RT5659_M_BST1_SM_L			(0x1 << 1)
+#define RT5659_M_BST1_SM_L_SFT			1
+#define RT5659_M_DAC_L2_SM_L			(0x1)
+#define RT5659_M_DAC_L2_SM_L_SFT		0
+
+/* SPK Right Mixer Control (0x0047) */
+#define RT5659_M_BST3_SM_R			(0x1 << 4)
+#define RT5659_M_BST3_SM_R_SFT			4
+#define RT5659_M_IN_R_SM_R			(0x1 << 3)
+#define RT5659_M_IN_R_SM_R_SFT			3
+#define RT5659_M_IN_L_SM_R			(0x1 << 2)
+#define RT5659_M_IN_L_SM_R_SFT			2
+#define RT5659_M_BST4_SM_R			(0x1 << 1)
+#define RT5659_M_BST4_SM_R_SFT			1
+#define RT5659_M_DAC_R2_SM_R			(0x1)
+#define RT5659_M_DAC_R2_SM_R_SFT		0
+
+/* SPO Amp Input and Gain Control (0x0048) */
+#define RT5659_M_DAC_L2_SPKOMIX			(0x1 << 13)
+#define RT5659_M_DAC_L2_SPKOMIX_SFT		13
+#define RT5659_M_SPKVOLL_SPKOMIX		(0x1 << 12)
+#define RT5659_M_SPKVOLL_SPKOMIX_SFT		12
+#define RT5659_M_DAC_R2_SPKOMIX			(0x1 << 9)
+#define RT5659_M_DAC_R2_SPKOMIX_SFT		9
+#define RT5659_M_SPKVOLR_SPKOMIX		(0x1 << 8)
+#define RT5659_M_SPKVOLR_SPKOMIX_SFT		8
+
+/* MONOMIX Input and Gain Control (0x004b) */
+#define RT5659_M_MONOVOL_MA			(0x1 << 9)
+#define RT5659_M_MONOVOL_MA_SFT			9
+#define RT5659_M_DAC_L2_MA			(0x1 << 8)
+#define RT5659_M_DAC_L2_MA_SFT			8
+#define RT5659_M_BST3_MM			(0x1 << 4)
+#define RT5659_M_BST3_MM_SFT			4
+#define RT5659_M_BST2_MM			(0x1 << 3)
+#define RT5659_M_BST2_MM_SFT			3
+#define RT5659_M_BST1_MM			(0x1 << 2)
+#define RT5659_M_BST1_MM_SFT			2
+#define RT5659_M_DAC_R2_MM			(0x1 << 1)
+#define RT5659_M_DAC_R2_MM_SFT			1
+#define RT5659_M_DAC_L2_MM			(0x1)
+#define RT5659_M_DAC_L2_MM_SFT			0
+
+/* Output Left Mixer Control 1 (0x004d) */
+#define RT5659_G_BST3_OM_L_MASK			(0x7 << 12)
+#define RT5659_G_BST3_OM_L_SFT			12
+#define RT5659_G_BST2_OM_L_MASK			(0x7 << 9)
+#define RT5659_G_BST2_OM_L_SFT			9
+#define RT5659_G_BST1_OM_L_MASK			(0x7 << 6)
+#define RT5659_G_BST1_OM_L_SFT			6
+#define RT5659_G_IN_L_OM_L_MASK			(0x7 << 3)
+#define RT5659_G_IN_L_OM_L_SFT			3
+#define RT5659_G_DAC_L2_OM_L_MASK		(0x7 << 0)
+#define RT5659_G_DAC_L2_OM_L_SFT		0
+
+/* Output Left Mixer Input Control (0x004e) */
+#define RT5659_M_BST3_OM_L			(0x1 << 4)
+#define RT5659_M_BST3_OM_L_SFT			4
+#define RT5659_M_BST2_OM_L			(0x1 << 3)
+#define RT5659_M_BST2_OM_L_SFT			3
+#define RT5659_M_BST1_OM_L			(0x1 << 2)
+#define RT5659_M_BST1_OM_L_SFT			2
+#define RT5659_M_IN_L_OM_L			(0x1 << 1)
+#define RT5659_M_IN_L_OM_L_SFT			1
+#define RT5659_M_DAC_L2_OM_L			(0x1)
+#define RT5659_M_DAC_L2_OM_L_SFT		0
+
+/* Output Right Mixer Input Control (0x0050) */
+#define RT5659_M_BST4_OM_R			(0x1 << 4)
+#define RT5659_M_BST4_OM_R_SFT			4
+#define RT5659_M_BST3_OM_R			(0x1 << 3)
+#define RT5659_M_BST3_OM_R_SFT			3
+#define RT5659_M_BST2_OM_R			(0x1 << 2)
+#define RT5659_M_BST2_OM_R_SFT			2
+#define RT5659_M_IN_R_OM_R			(0x1 << 1)
+#define RT5659_M_IN_R_OM_R_SFT			1
+#define RT5659_M_DAC_R2_OM_R			(0x1)
+#define RT5659_M_DAC_R2_OM_R_SFT		0
+
+/* LOUT Mixer Control (0x0052) */
+#define RT5659_M_DAC_L2_LM			(0x1 << 15)
+#define RT5659_M_DAC_L2_LM_SFT			15
+#define RT5659_M_DAC_R2_LM			(0x1 << 14)
+#define RT5659_M_DAC_R2_LM_SFT			14
+#define RT5659_M_OV_L_LM			(0x1 << 13)
+#define RT5659_M_OV_L_LM_SFT			13
+#define RT5659_M_OV_R_LM			(0x1 << 12)
+#define RT5659_M_OV_R_LM_SFT			12
+
+/* Power Management for Digital 1 (0x0061) */
+#define RT5659_PWR_I2S1				(0x1 << 15)
+#define RT5659_PWR_I2S1_BIT			15
+#define RT5659_PWR_I2S2				(0x1 << 14)
+#define RT5659_PWR_I2S2_BIT			14
+#define RT5659_PWR_I2S3				(0x1 << 13)
+#define RT5659_PWR_I2S3_BIT			13
+#define RT5659_PWR_SPDIF			(0x1 << 12)
+#define RT5659_PWR_SPDIF_BIT			12
+#define RT5659_PWR_DAC_L1			(0x1 << 11)
+#define RT5659_PWR_DAC_L1_BIT			11
+#define RT5659_PWR_DAC_R1			(0x1 << 10)
+#define RT5659_PWR_DAC_R1_BIT			10
+#define RT5659_PWR_DAC_L2			(0x1 << 9)
+#define RT5659_PWR_DAC_L2_BIT			9
+#define RT5659_PWR_DAC_R2			(0x1 << 8)
+#define RT5659_PWR_DAC_R2_BIT			8
+#define RT5659_PWR_LDO				(0x1 << 7)
+#define RT5659_PWR_LDO_BIT			7
+#define RT5659_PWR_ADC_L1			(0x1 << 4)
+#define RT5659_PWR_ADC_L1_BIT			4
+#define RT5659_PWR_ADC_R1			(0x1 << 3)
+#define RT5659_PWR_ADC_R1_BIT			3
+#define RT5659_PWR_ADC_L2			(0x1 << 2)
+#define RT5659_PWR_ADC_L2_BIT			4
+#define RT5659_PWR_ADC_R2			(0x1 << 1)
+#define RT5659_PWR_ADC_R2_BIT			1
+#define RT5659_PWR_CLS_D			(0x1)
+#define RT5659_PWR_CLS_D_BIT			0
+
+/* Power Management for Digital 2 (0x0062) */
+#define RT5659_PWR_ADC_S1F			(0x1 << 15)
+#define RT5659_PWR_ADC_S1F_BIT			15
+#define RT5659_PWR_ADC_S2F			(0x1 << 14)
+#define RT5659_PWR_ADC_S2F_BIT			14
+#define RT5659_PWR_ADC_MF_L			(0x1 << 13)
+#define RT5659_PWR_ADC_MF_L_BIT			13
+#define RT5659_PWR_ADC_MF_R			(0x1 << 12)
+#define RT5659_PWR_ADC_MF_R_BIT			12
+#define RT5659_PWR_DAC_S1F			(0x1 << 10)
+#define RT5659_PWR_DAC_S1F_BIT			10
+#define RT5659_PWR_DAC_MF_L			(0x1 << 9)
+#define RT5659_PWR_DAC_MF_L_BIT			9
+#define RT5659_PWR_DAC_MF_R			(0x1 << 8)
+#define RT5659_PWR_DAC_MF_R_BIT			8
+#define RT5659_PWR_PDM1				(0x1 << 7)
+#define RT5659_PWR_PDM1_BIT			7
+
+/* Power Management for Analog 1 (0x0063) */
+#define RT5659_PWR_VREF1			(0x1 << 15)
+#define RT5659_PWR_VREF1_BIT			15
+#define RT5659_PWR_FV1				(0x1 << 14)
+#define RT5659_PWR_FV1_BIT			14
+#define RT5659_PWR_VREF2			(0x1 << 13)
+#define RT5659_PWR_VREF2_BIT			13
+#define RT5659_PWR_FV2				(0x1 << 12)
+#define RT5659_PWR_FV2_BIT			12
+#define RT5659_PWR_VREF3			(0x1 << 11)
+#define RT5659_PWR_VREF3_BIT			11
+#define RT5659_PWR_FV3				(0x1 << 10)
+#define RT5659_PWR_FV3_BIT			10
+#define RT5659_PWR_MB				(0x1 << 9)
+#define RT5659_PWR_MB_BIT			9
+#define RT5659_PWR_LM				(0x1 << 8)
+#define RT5659_PWR_LM_BIT			8
+#define RT5659_PWR_BG				(0x1 << 7)
+#define RT5659_PWR_BG_BIT			7
+#define RT5659_PWR_MA				(0x1 << 6)
+#define RT5659_PWR_MA_BIT			6
+#define RT5659_PWR_HA_L				(0x1 << 5)
+#define RT5659_PWR_HA_L_BIT			5
+#define RT5659_PWR_HA_R				(0x1 << 4)
+#define RT5659_PWR_HA_R_BIT			4
+
+/* Power Management for Analog 2 (0x0064) */
+#define RT5659_PWR_BST1				(0x1 << 15)
+#define RT5659_PWR_BST1_BIT			15
+#define RT5659_PWR_BST2				(0x1 << 14)
+#define RT5659_PWR_BST2_BIT			14
+#define RT5659_PWR_BST3				(0x1 << 13)
+#define RT5659_PWR_BST3_BIT			13
+#define RT5659_PWR_BST4				(0x1 << 12)
+#define RT5659_PWR_BST4_BIT			12
+#define RT5659_PWR_MB1				(0x1 << 11)
+#define RT5659_PWR_MB1_BIT			11
+#define RT5659_PWR_MB2				(0x1 << 10)
+#define RT5659_PWR_MB2_BIT			10
+#define RT5659_PWR_MB3				(0x1 << 9)
+#define RT5659_PWR_MB3_BIT			9
+#define RT5659_PWR_BST1_P			(0x1 << 6)
+#define RT5659_PWR_BST1_P_BIT			6
+#define RT5659_PWR_BST2_P			(0x1 << 5)
+#define RT5659_PWR_BST2_P_BIT			5
+#define RT5659_PWR_BST3_P			(0x1 << 4)
+#define RT5659_PWR_BST3_P_BIT			4
+#define RT5659_PWR_BST4_P			(0x1 << 3)
+#define RT5659_PWR_BST4_P_BIT			3
+#define RT5659_PWR_JD1				(0x1 << 2)
+#define RT5659_PWR_JD1_BIT			2
+#define RT5659_PWR_JD2				(0x1 << 1)
+#define RT5659_PWR_JD2_BIT			1
+#define RT5659_PWR_JD3				(0x1)
+#define RT5659_PWR_JD3_BIT			0
+
+/* Power Management for Analog 3 (0x0065) */
+#define RT5659_PWR_BST_L			(0x1 << 8)
+#define RT5659_PWR_BST_L_BIT			8
+#define RT5659_PWR_BST_R			(0x1 << 7)
+#define RT5659_PWR_BST_R_BIT			7
+#define RT5659_PWR_PLL				(0x1 << 6)
+#define RT5659_PWR_PLL_BIT			6
+#define RT5659_PWR_LDO5				(0x1 << 5)
+#define RT5659_PWR_LDO5_BIT			5
+#define RT5659_PWR_LDO4				(0x1 << 4)
+#define RT5659_PWR_LDO4_BIT			4
+#define RT5659_PWR_LDO3				(0x1 << 3)
+#define RT5659_PWR_LDO3_BIT			3
+#define RT5659_PWR_LDO2				(0x1 << 2)
+#define RT5659_PWR_LDO2_BIT			2
+#define RT5659_PWR_SVD				(0x1 << 1)
+#define RT5659_PWR_SVD_BIT			1
+
+/* Power Management for Mixer (0x0066) */
+#define RT5659_PWR_OM_L				(0x1 << 15)
+#define RT5659_PWR_OM_L_BIT			15
+#define RT5659_PWR_OM_R				(0x1 << 14)
+#define RT5659_PWR_OM_R_BIT			14
+#define RT5659_PWR_SM_L				(0x1 << 13)
+#define RT5659_PWR_SM_L_BIT			13
+#define RT5659_PWR_SM_R				(0x1 << 12)
+#define RT5659_PWR_SM_R_BIT			12
+#define RT5659_PWR_RM1_L			(0x1 << 11)
+#define RT5659_PWR_RM1_L_BIT			11
+#define RT5659_PWR_RM1_R			(0x1 << 10)
+#define RT5659_PWR_RM1_R_BIT			10
+#define RT5659_PWR_MM				(0x1 << 8)
+#define RT5659_PWR_MM_BIT			8
+#define RT5659_PWR_RM2_L			(0x1 << 3)
+#define RT5659_PWR_RM2_L_BIT			3
+#define RT5659_PWR_RM2_R			(0x1 << 2)
+#define RT5659_PWR_RM2_R_BIT			2
+
+/* Power Management for Volume (0x0067) */
+#define RT5659_PWR_SV_L				(0x1 << 15)
+#define RT5659_PWR_SV_L_BIT			15
+#define RT5659_PWR_SV_R				(0x1 << 14)
+#define RT5659_PWR_SV_R_BIT			14
+#define RT5659_PWR_OV_L				(0x1 << 13)
+#define RT5659_PWR_OV_L_BIT			13
+#define RT5659_PWR_OV_R				(0x1 << 12)
+#define RT5659_PWR_OV_R_BIT			12
+#define RT5659_PWR_IN_L				(0x1 << 9)
+#define RT5659_PWR_IN_L_BIT			9
+#define RT5659_PWR_IN_R				(0x1 << 8)
+#define RT5659_PWR_IN_R_BIT			8
+#define RT5659_PWR_MV				(0x1 << 7)
+#define RT5659_PWR_MV_BIT			7
+#define RT5659_PWR_MIC_DET			(0x1 << 5)
+#define RT5659_PWR_MIC_DET_BIT			5
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x0070 0x0071 0x0072) */
+#define RT5659_I2S_MS_MASK			(0x1 << 15)
+#define RT5659_I2S_MS_SFT			15
+#define RT5659_I2S_MS_M				(0x0 << 15)
+#define RT5659_I2S_MS_S				(0x1 << 15)
+#define RT5659_I2S_O_CP_MASK			(0x3 << 12)
+#define RT5659_I2S_O_CP_SFT			12
+#define RT5659_I2S_O_CP_OFF			(0x0 << 12)
+#define RT5659_I2S_O_CP_U_LAW			(0x1 << 12)
+#define RT5659_I2S_O_CP_A_LAW			(0x2 << 12)
+#define RT5659_I2S_I_CP_MASK			(0x3 << 10)
+#define RT5659_I2S_I_CP_SFT			10
+#define RT5659_I2S_I_CP_OFF			(0x0 << 10)
+#define RT5659_I2S_I_CP_U_LAW			(0x1 << 10)
+#define RT5659_I2S_I_CP_A_LAW			(0x2 << 10)
+#define RT5659_I2S_BP_MASK			(0x1 << 8)
+#define RT5659_I2S_BP_SFT			8
+#define RT5659_I2S_BP_NOR			(0x0 << 8)
+#define RT5659_I2S_BP_INV			(0x1 << 8)
+#define RT5659_I2S_DL_MASK			(0x3 << 4)
+#define RT5659_I2S_DL_SFT			4
+#define RT5659_I2S_DL_16			(0x0 << 4)
+#define RT5659_I2S_DL_20			(0x1 << 4)
+#define RT5659_I2S_DL_24			(0x2 << 4)
+#define RT5659_I2S_DL_8				(0x3 << 4)
+#define RT5659_I2S_DF_MASK			(0x7)
+#define RT5659_I2S_DF_SFT			0
+#define RT5659_I2S_DF_I2S			(0x0)
+#define RT5659_I2S_DF_LEFT			(0x1)
+#define RT5659_I2S_DF_PCM_A			(0x2)
+#define RT5659_I2S_DF_PCM_B			(0x3)
+#define RT5659_I2S_DF_PCM_A_N			(0x6)
+#define RT5659_I2S_DF_PCM_B_N			(0x7)
+
+/* ADC/DAC Clock Control 1 (0x0073) */
+#define RT5659_I2S_PD1_MASK			(0x7 << 12)
+#define RT5659_I2S_PD1_SFT			12
+#define RT5659_I2S_PD1_1			(0x0 << 12)
+#define RT5659_I2S_PD1_2			(0x1 << 12)
+#define RT5659_I2S_PD1_3			(0x2 << 12)
+#define RT5659_I2S_PD1_4			(0x3 << 12)
+#define RT5659_I2S_PD1_6			(0x4 << 12)
+#define RT5659_I2S_PD1_8			(0x5 << 12)
+#define RT5659_I2S_PD1_12			(0x6 << 12)
+#define RT5659_I2S_PD1_16			(0x7 << 12)
+#define RT5659_I2S_BCLK_MS2_MASK		(0x1 << 11)
+#define RT5659_I2S_BCLK_MS2_SFT			11
+#define RT5659_I2S_BCLK_MS2_32			(0x0 << 11)
+#define RT5659_I2S_BCLK_MS2_64			(0x1 << 11)
+#define RT5659_I2S_PD2_MASK			(0x7 << 8)
+#define RT5659_I2S_PD2_SFT			8
+#define RT5659_I2S_PD2_1			(0x0 << 8)
+#define RT5659_I2S_PD2_2			(0x1 << 8)
+#define RT5659_I2S_PD2_3			(0x2 << 8)
+#define RT5659_I2S_PD2_4			(0x3 << 8)
+#define RT5659_I2S_PD2_6			(0x4 << 8)
+#define RT5659_I2S_PD2_8			(0x5 << 8)
+#define RT5659_I2S_PD2_12			(0x6 << 8)
+#define RT5659_I2S_PD2_16			(0x7 << 8)
+#define RT5659_I2S_BCLK_MS3_MASK		(0x1 << 7)
+#define RT5659_I2S_BCLK_MS3_SFT			7
+#define RT5659_I2S_BCLK_MS3_32			(0x0 << 7)
+#define RT5659_I2S_BCLK_MS3_64			(0x1 << 7)
+#define RT5659_I2S_PD3_MASK			(0x7 << 4)
+#define RT5659_I2S_PD3_SFT			4
+#define RT5659_I2S_PD3_1			(0x0 << 4)
+#define RT5659_I2S_PD3_2			(0x1 << 4)
+#define RT5659_I2S_PD3_3			(0x2 << 4)
+#define RT5659_I2S_PD3_4			(0x3 << 4)
+#define RT5659_I2S_PD3_6			(0x4 << 4)
+#define RT5659_I2S_PD3_8			(0x5 << 4)
+#define RT5659_I2S_PD3_12			(0x6 << 4)
+#define RT5659_I2S_PD3_16			(0x7 << 4)
+#define RT5659_DAC_OSR_MASK			(0x3 << 2)
+#define RT5659_DAC_OSR_SFT			2
+#define RT5659_DAC_OSR_128			(0x0 << 2)
+#define RT5659_DAC_OSR_64			(0x1 << 2)
+#define RT5659_DAC_OSR_32			(0x2 << 2)
+#define RT5659_DAC_OSR_16			(0x3 << 2)
+#define RT5659_ADC_OSR_MASK			(0x3)
+#define RT5659_ADC_OSR_SFT			0
+#define RT5659_ADC_OSR_128			(0x0)
+#define RT5659_ADC_OSR_64			(0x1)
+#define RT5659_ADC_OSR_32			(0x2)
+#define RT5659_ADC_OSR_16			(0x3)
+
+/* Digital Microphone Control (0x0075) */
+#define RT5659_DMIC_1_EN_MASK			(0x1 << 15)
+#define RT5659_DMIC_1_EN_SFT			15
+#define RT5659_DMIC_1_DIS			(0x0 << 15)
+#define RT5659_DMIC_1_EN			(0x1 << 15)
+#define RT5659_DMIC_2_EN_MASK			(0x1 << 14)
+#define RT5659_DMIC_2_EN_SFT			14
+#define RT5659_DMIC_2_DIS			(0x0 << 14)
+#define RT5659_DMIC_2_EN			(0x1 << 14)
+#define RT5659_DMIC_1L_LH_MASK			(0x1 << 13)
+#define RT5659_DMIC_1L_LH_SFT			13
+#define RT5659_DMIC_1L_LH_RISING		(0x0 << 13)
+#define RT5659_DMIC_1L_LH_FALLING		(0x1 << 13)
+#define RT5659_DMIC_1R_LH_MASK			(0x1 << 12)
+#define RT5659_DMIC_1R_LH_SFT			12
+#define RT5659_DMIC_1R_LH_RISING		(0x0 << 12)
+#define RT5659_DMIC_1R_LH_FALLING		(0x1 << 12)
+#define RT5659_DMIC_2_DP_MASK			(0x3 << 10)
+#define RT5659_DMIC_2_DP_SFT			10
+#define RT5659_DMIC_2_DP_GPIO6			(0x0 << 10)
+#define RT5659_DMIC_2_DP_GPIO10			(0x1 << 10)
+#define RT5659_DMIC_2_DP_GPIO12			(0x2 << 10)
+#define RT5659_DMIC_2_DP_IN2P			(0x3 << 10)
+#define RT5659_DMIC_CLK_MASK			(0x7 << 5)
+#define RT5659_DMIC_CLK_SFT			5
+#define RT5659_DMIC_1_DP_MASK			(0x3 << 0)
+#define RT5659_DMIC_1_DP_SFT			0
+#define RT5659_DMIC_1_DP_GPIO5			(0x0 << 0)
+#define RT5659_DMIC_1_DP_GPIO9			(0x1 << 0)
+#define RT5659_DMIC_1_DP_GPIO11			(0x2 << 0)
+#define RT5659_DMIC_1_DP_IN2N			(0x3 << 0)
+
+/* TDM control 1 (0x0078)*/
+#define RT5659_DS_ADC_SLOT01_SFT		14
+#define RT5659_DS_ADC_SLOT23_SFT		12
+#define RT5659_DS_ADC_SLOT45_SFT		10
+#define RT5659_DS_ADC_SLOT67_SFT		8
+#define RT5659_ADCDAT_SRC_MASK			0x1f
+#define RT5659_ADCDAT_SRC_SFT			0
+
+/* Global Clock Control (0x0080) */
+#define RT5659_SCLK_SRC_MASK			(0x3 << 14)
+#define RT5659_SCLK_SRC_SFT			14
+#define RT5659_SCLK_SRC_MCLK			(0x0 << 14)
+#define RT5659_SCLK_SRC_PLL1			(0x1 << 14)
+#define RT5659_SCLK_SRC_RCCLK			(0x2 << 14)
+#define RT5659_PLL1_SRC_MASK			(0x7 << 11)
+#define RT5659_PLL1_SRC_SFT			11
+#define RT5659_PLL1_SRC_MCLK			(0x0 << 11)
+#define RT5659_PLL1_SRC_BCLK1			(0x1 << 11)
+#define RT5659_PLL1_SRC_BCLK2			(0x2 << 11)
+#define RT5659_PLL1_SRC_BCLK3			(0x3 << 11)
+#define RT5659_PLL1_PD_MASK			(0x1 << 3)
+#define RT5659_PLL1_PD_SFT			3
+#define RT5659_PLL1_PD_1			(0x0 << 3)
+#define RT5659_PLL1_PD_2			(0x1 << 3)
+
+#define RT5659_PLL_INP_MAX			40000000
+#define RT5659_PLL_INP_MIN			256000
+/* PLL M/N/K Code Control 1 (0x0081) */
+#define RT5659_PLL_N_MAX			0x001ff
+#define RT5659_PLL_N_MASK			(RT5659_PLL_N_MAX << 7)
+#define RT5659_PLL_N_SFT			7
+#define RT5659_PLL_K_MAX			0x001f
+#define RT5659_PLL_K_MASK			(RT5659_PLL_K_MAX)
+#define RT5659_PLL_K_SFT			0
+
+/* PLL M/N/K Code Control 2 (0x0082) */
+#define RT5659_PLL_M_MAX			0x00f
+#define RT5659_PLL_M_MASK			(RT5659_PLL_M_MAX << 12)
+#define RT5659_PLL_M_SFT			12
+#define RT5659_PLL_M_BP				(0x1 << 11)
+#define RT5659_PLL_M_BP_SFT			11
+
+/* PLL tracking mode 1 (0x0083) */
+#define RT5659_I2S3_ASRC_MASK			(0x1 << 13)
+#define RT5659_I2S3_ASRC_SFT			13
+#define RT5659_I2S2_ASRC_MASK			(0x1 << 12)
+#define RT5659_I2S2_ASRC_SFT			12
+#define RT5659_I2S1_ASRC_MASK			(0x1 << 11)
+#define RT5659_I2S1_ASRC_SFT			11
+#define RT5659_DAC_STO_ASRC_MASK		(0x1 << 10)
+#define RT5659_DAC_STO_ASRC_SFT			10
+#define RT5659_DAC_MONO_L_ASRC_MASK		(0x1 << 9)
+#define RT5659_DAC_MONO_L_ASRC_SFT		9
+#define RT5659_DAC_MONO_R_ASRC_MASK		(0x1 << 8)
+#define RT5659_DAC_MONO_R_ASRC_SFT		8
+#define RT5659_DMIC_STO1_ASRC_MASK		(0x1 << 7)
+#define RT5659_DMIC_STO1_ASRC_SFT		7
+#define RT5659_DMIC_MONO_L_ASRC_MASK		(0x1 << 5)
+#define RT5659_DMIC_MONO_L_ASRC_SFT		5
+#define RT5659_DMIC_MONO_R_ASRC_MASK		(0x1 << 4)
+#define RT5659_DMIC_MONO_R_ASRC_SFT		4
+#define RT5659_ADC_STO1_ASRC_MASK		(0x1 << 3)
+#define RT5659_ADC_STO1_ASRC_SFT		3
+#define RT5659_ADC_MONO_L_ASRC_MASK		(0x1 << 1)
+#define RT5659_ADC_MONO_L_ASRC_SFT		1
+#define RT5659_ADC_MONO_R_ASRC_MASK		(0x1)
+#define RT5659_ADC_MONO_R_ASRC_SFT		0
+
+/* PLL tracking mode 2 (0x0084)*/
+#define RT5659_DA_STO_T_MASK			(0x7 << 12)
+#define RT5659_DA_STO_T_SFT			12
+#define RT5659_DA_MONO_L_T_MASK			(0x7 << 8)
+#define RT5659_DA_MONO_L_T_SFT			8
+#define RT5659_DA_MONO_R_T_MASK			(0x7 << 4)
+#define RT5659_DA_MONO_R_T_SFT			4
+#define RT5659_AD_STO1_T_MASK			(0x7)
+#define RT5659_AD_STO1_T_SFT			0
+
+/* PLL tracking mode 3 (0x0085)*/
+#define RT5659_AD_STO2_T_MASK			(0x7 << 8)
+#define RT5659_AD_STO2_T_SFT			8
+#define RT5659_AD_MONO_L_T_MASK			(0x7 << 4)
+#define RT5659_AD_MONO_L_T_SFT			4
+#define RT5659_AD_MONO_R_T_MASK			(0x7)
+#define RT5659_AD_MONO_R_T_SFT			0
+
+/* ASRC Control 4 (0x0086) */
+#define RT5659_I2S1_RATE_MASK			(0xf << 12)
+#define RT5659_I2S1_RATE_SFT			12
+#define RT5659_I2S2_RATE_MASK			(0xf << 8)
+#define RT5659_I2S2_RATE_SFT			8
+#define RT5659_I2S3_RATE_MASK			(0xf << 4)
+#define RT5659_I2S3_RATE_SFT			4
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5659_SMT_TRIG_MASK			(0x1 << 15)
+#define RT5659_SMT_TRIG_SFT			15
+#define RT5659_SMT_TRIG_DIS			(0x0 << 15)
+#define RT5659_SMT_TRIG_EN			(0x1 << 15)
+#define RT5659_HP_L_SMT_MASK			(0x1 << 9)
+#define RT5659_HP_L_SMT_SFT			9
+#define RT5659_HP_L_SMT_DIS			(0x0 << 9)
+#define RT5659_HP_L_SMT_EN			(0x1 << 9)
+#define RT5659_HP_R_SMT_MASK			(0x1 << 8)
+#define RT5659_HP_R_SMT_SFT			8
+#define RT5659_HP_R_SMT_DIS			(0x0 << 8)
+#define RT5659_HP_R_SMT_EN			(0x1 << 8)
+#define RT5659_HP_CD_PD_MASK			(0x1 << 7)
+#define RT5659_HP_CD_PD_SFT			7
+#define RT5659_HP_CD_PD_DIS			(0x0 << 7)
+#define RT5659_HP_CD_PD_EN			(0x1 << 7)
+#define RT5659_RSTN_MASK			(0x1 << 6)
+#define RT5659_RSTN_SFT				6
+#define RT5659_RSTN_DIS				(0x0 << 6)
+#define RT5659_RSTN_EN				(0x1 << 6)
+#define RT5659_RSTP_MASK			(0x1 << 5)
+#define RT5659_RSTP_SFT				5
+#define RT5659_RSTP_DIS				(0x0 << 5)
+#define RT5659_RSTP_EN				(0x1 << 5)
+#define RT5659_HP_CO_MASK			(0x1 << 4)
+#define RT5659_HP_CO_SFT			4
+#define RT5659_HP_CO_DIS			(0x0 << 4)
+#define RT5659_HP_CO_EN				(0x1 << 4)
+#define RT5659_HP_CP_MASK			(0x1 << 3)
+#define RT5659_HP_CP_SFT			3
+#define RT5659_HP_CP_PD				(0x0 << 3)
+#define RT5659_HP_CP_PU				(0x1 << 3)
+#define RT5659_HP_SG_MASK			(0x1 << 2)
+#define RT5659_HP_SG_SFT			2
+#define RT5659_HP_SG_DIS			(0x0 << 2)
+#define RT5659_HP_SG_EN				(0x1 << 2)
+#define RT5659_HP_DP_MASK			(0x1 << 1)
+#define RT5659_HP_DP_SFT			1
+#define RT5659_HP_DP_PD				(0x0 << 1)
+#define RT5659_HP_DP_PU				(0x1 << 1)
+#define RT5659_HP_CB_MASK			(0x1)
+#define RT5659_HP_CB_SFT			0
+#define RT5659_HP_CB_PD				(0x0)
+#define RT5659_HP_CB_PU				(0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5659_DEPOP_MASK			(0x1 << 13)
+#define RT5659_DEPOP_SFT			13
+#define RT5659_DEPOP_AUTO			(0x0 << 13)
+#define RT5659_DEPOP_MAN			(0x1 << 13)
+#define RT5659_RAMP_MASK			(0x1 << 12)
+#define RT5659_RAMP_SFT				12
+#define RT5659_RAMP_DIS				(0x0 << 12)
+#define RT5659_RAMP_EN				(0x1 << 12)
+#define RT5659_BPS_MASK				(0x1 << 11)
+#define RT5659_BPS_SFT				11
+#define RT5659_BPS_DIS				(0x0 << 11)
+#define RT5659_BPS_EN				(0x1 << 11)
+#define RT5659_FAST_UPDN_MASK			(0x1 << 10)
+#define RT5659_FAST_UPDN_SFT			10
+#define RT5659_FAST_UPDN_DIS			(0x0 << 10)
+#define RT5659_FAST_UPDN_EN			(0x1 << 10)
+#define RT5659_MRES_MASK			(0x3 << 8)
+#define RT5659_MRES_SFT				8
+#define RT5659_MRES_15MO			(0x0 << 8)
+#define RT5659_MRES_25MO			(0x1 << 8)
+#define RT5659_MRES_35MO			(0x2 << 8)
+#define RT5659_MRES_45MO			(0x3 << 8)
+#define RT5659_VLO_MASK				(0x1 << 7)
+#define RT5659_VLO_SFT				7
+#define RT5659_VLO_3V				(0x0 << 7)
+#define RT5659_VLO_32V				(0x1 << 7)
+#define RT5659_DIG_DP_MASK			(0x1 << 6)
+#define RT5659_DIG_DP_SFT			6
+#define RT5659_DIG_DP_DIS			(0x0 << 6)
+#define RT5659_DIG_DP_EN			(0x1 << 6)
+#define RT5659_DP_TH_MASK			(0x3 << 4)
+#define RT5659_DP_TH_SFT			4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5659_CP_SYS_MASK			(0x7 << 12)
+#define RT5659_CP_SYS_SFT			12
+#define RT5659_CP_FQ1_MASK			(0x7 << 8)
+#define RT5659_CP_FQ1_SFT			8
+#define RT5659_CP_FQ2_MASK			(0x7 << 4)
+#define RT5659_CP_FQ2_SFT			4
+#define RT5659_CP_FQ3_MASK			(0x7)
+#define RT5659_CP_FQ3_SFT			0
+#define RT5659_CP_FQ_1_5_KHZ			0
+#define RT5659_CP_FQ_3_KHZ			1
+#define RT5659_CP_FQ_6_KHZ			2
+#define RT5659_CP_FQ_12_KHZ			3
+#define RT5659_CP_FQ_24_KHZ			4
+#define RT5659_CP_FQ_48_KHZ			5
+#define RT5659_CP_FQ_96_KHZ			6
+#define RT5659_CP_FQ_192_KHZ			7
+
+/* HPOUT charge pump 1 (0x0091) */
+#define RT5659_OSW_L_MASK			(0x1 << 11)
+#define RT5659_OSW_L_SFT			11
+#define RT5659_OSW_L_DIS			(0x0 << 11)
+#define RT5659_OSW_L_EN				(0x1 << 11)
+#define RT5659_OSW_R_MASK			(0x1 << 10)
+#define RT5659_OSW_R_SFT			10
+#define RT5659_OSW_R_DIS			(0x0 << 10)
+#define RT5659_OSW_R_EN				(0x1 << 10)
+#define RT5659_PM_HP_MASK			(0x3 << 8)
+#define RT5659_PM_HP_SFT			8
+#define RT5659_PM_HP_LV				(0x0 << 8)
+#define RT5659_PM_HP_MV				(0x1 << 8)
+#define RT5659_PM_HP_HV				(0x2 << 8)
+#define RT5659_IB_HP_MASK			(0x3 << 6)
+#define RT5659_IB_HP_SFT			6
+#define RT5659_IB_HP_125IL			(0x0 << 6)
+#define RT5659_IB_HP_25IL			(0x1 << 6)
+#define RT5659_IB_HP_5IL			(0x2 << 6)
+#define RT5659_IB_HP_1IL			(0x3 << 6)
+
+/* PV detection and SPK gain control (0x92) */
+#define RT5659_PVDD_DET_MASK			(0x1 << 15)
+#define RT5659_PVDD_DET_SFT			15
+#define RT5659_PVDD_DET_DIS			(0x0 << 15)
+#define RT5659_PVDD_DET_EN			(0x1 << 15)
+#define RT5659_SPK_AG_MASK			(0x1 << 14)
+#define RT5659_SPK_AG_SFT			14
+#define RT5659_SPK_AG_DIS			(0x0 << 14)
+#define RT5659_SPK_AG_EN			(0x1 << 14)
+
+/* Micbias Control (0x93) */
+#define RT5659_MIC1_BS_MASK			(0x1 << 15)
+#define RT5659_MIC1_BS_SFT			15
+#define RT5659_MIC1_BS_9AV			(0x0 << 15)
+#define RT5659_MIC1_BS_75AV			(0x1 << 15)
+#define RT5659_MIC2_BS_MASK			(0x1 << 14)
+#define RT5659_MIC2_BS_SFT			14
+#define RT5659_MIC2_BS_9AV			(0x0 << 14)
+#define RT5659_MIC2_BS_75AV			(0x1 << 14)
+#define RT5659_MIC1_CLK_MASK			(0x1 << 13)
+#define RT5659_MIC1_CLK_SFT			13
+#define RT5659_MIC1_CLK_DIS			(0x0 << 13)
+#define RT5659_MIC1_CLK_EN			(0x1 << 13)
+#define RT5659_MIC2_CLK_MASK			(0x1 << 12)
+#define RT5659_MIC2_CLK_SFT			12
+#define RT5659_MIC2_CLK_DIS			(0x0 << 12)
+#define RT5659_MIC2_CLK_EN			(0x1 << 12)
+#define RT5659_MIC1_OVCD_MASK			(0x1 << 11)
+#define RT5659_MIC1_OVCD_SFT			11
+#define RT5659_MIC1_OVCD_DIS			(0x0 << 11)
+#define RT5659_MIC1_OVCD_EN			(0x1 << 11)
+#define RT5659_MIC1_OVTH_MASK			(0x3 << 9)
+#define RT5659_MIC1_OVTH_SFT			9
+#define RT5659_MIC1_OVTH_600UA			(0x0 << 9)
+#define RT5659_MIC1_OVTH_1500UA			(0x1 << 9)
+#define RT5659_MIC1_OVTH_2000UA			(0x2 << 9)
+#define RT5659_MIC2_OVCD_MASK			(0x1 << 8)
+#define RT5659_MIC2_OVCD_SFT			8
+#define RT5659_MIC2_OVCD_DIS			(0x0 << 8)
+#define RT5659_MIC2_OVCD_EN			(0x1 << 8)
+#define RT5659_MIC2_OVTH_MASK			(0x3 << 6)
+#define RT5659_MIC2_OVTH_SFT			6
+#define RT5659_MIC2_OVTH_600UA			(0x0 << 6)
+#define RT5659_MIC2_OVTH_1500UA			(0x1 << 6)
+#define RT5659_MIC2_OVTH_2000UA			(0x2 << 6)
+#define RT5659_PWR_MB_MASK			(0x1 << 5)
+#define RT5659_PWR_MB_SFT			5
+#define RT5659_PWR_MB_PD			(0x0 << 5)
+#define RT5659_PWR_MB_PU			(0x1 << 5)
+#define RT5659_PWR_CLK25M_MASK			(0x1 << 4)
+#define RT5659_PWR_CLK25M_SFT			4
+#define RT5659_PWR_CLK25M_PD			(0x0 << 4)
+#define RT5659_PWR_CLK25M_PU			(0x1 << 4)
+
+/* REC Mixer 2 Left Control 2 (0x009c) */
+#define RT5659_M_BST1_RM2_L			(0x1 << 5)
+#define RT5659_M_BST1_RM2_L_SFT			5
+#define RT5659_M_BST2_RM2_L			(0x1 << 4)
+#define RT5659_M_BST2_RM2_L_SFT			4
+#define RT5659_M_BST3_RM2_L			(0x1 << 3)
+#define RT5659_M_BST3_RM2_L_SFT			3
+#define RT5659_M_BST4_RM2_L			(0x1 << 2)
+#define RT5659_M_BST4_RM2_L_SFT			2
+#define RT5659_M_OUTVOLL_RM2_L			(0x1 << 1)
+#define RT5659_M_OUTVOLL_RM2_L_SFT		1
+#define RT5659_M_SPKVOL_RM2_L			(0x1)
+#define RT5659_M_SPKVOL_RM2_L_SFT		0
+
+/* REC Mixer 2 Right Control 2 (0x009e) */
+#define RT5659_M_BST1_RM2_R			(0x1 << 5)
+#define RT5659_M_BST1_RM2_R_SFT			5
+#define RT5659_M_BST2_RM2_R			(0x1 << 4)
+#define RT5659_M_BST2_RM2_R_SFT			4
+#define RT5659_M_BST3_RM2_R			(0x1 << 3)
+#define RT5659_M_BST3_RM2_R_SFT			3
+#define RT5659_M_BST4_RM2_R			(0x1 << 2)
+#define RT5659_M_BST4_RM2_R_SFT			2
+#define RT5659_M_OUTVOLR_RM2_R			(0x1 << 1)
+#define RT5659_M_OUTVOLR_RM2_R_SFT		1
+#define RT5659_M_MONOVOL_RM2_R			(0x1)
+#define RT5659_M_MONOVOL_RM2_R_SFT		0
+
+/* Class D Output Control (0x00a0) */
+#define RT5659_POW_CLSD_DB_MASK			(0x1 << 9)
+#define RT5659_POW_CLSD_DB_EN			(0x1 << 9)
+#define RT5659_POW_CLSD_DB_DIS			(0x0 << 9)
+
+/* EQ Control 1 (0x00b0) */
+#define RT5659_EQ_SRC_DAC			(0x0 << 15)
+#define RT5659_EQ_SRC_ADC			(0x1 << 15)
+#define RT5659_EQ_UPD				(0x1 << 14)
+#define RT5659_EQ_UPD_BIT			14
+#define RT5659_EQ_CD_MASK			(0x1 << 13)
+#define RT5659_EQ_CD_SFT			13
+#define RT5659_EQ_CD_DIS			(0x0 << 13)
+#define RT5659_EQ_CD_EN				(0x1 << 13)
+#define RT5659_EQ_DITH_MASK			(0x3 << 8)
+#define RT5659_EQ_DITH_SFT			8
+#define RT5659_EQ_DITH_NOR			(0x0 << 8)
+#define RT5659_EQ_DITH_LSB			(0x1 << 8)
+#define RT5659_EQ_DITH_LSB_1			(0x2 << 8)
+#define RT5659_EQ_DITH_LSB_2			(0x3 << 8)
+
+/* IRQ Control 1 (0x00b7) */
+#define RT5659_JD1_1_EN_MASK			(0x1 << 15)
+#define RT5659_JD1_1_EN_SFT			15
+#define RT5659_JD1_1_DIS			(0x0 << 15)
+#define RT5659_JD1_1_EN				(0x1 << 15)
+#define RT5659_JD1_2_EN_MASK			(0x1 << 12)
+#define RT5659_JD1_2_EN_SFT			12
+#define RT5659_JD1_2_DIS			(0x0 << 12)
+#define RT5659_JD1_2_EN				(0x1 << 12)
+#define RT5659_IL_IRQ_MASK			(0x1 << 3)
+#define RT5659_IL_IRQ_DIS			(0x0 << 3)
+#define RT5659_IL_IRQ_EN			(0x1 << 3)
+
+/* IRQ Control 5 (0x00ba) */
+#define RT5659_IRQ_JD_EN			(0x1 << 3)
+#define RT5659_IRQ_JD_EN_SFT			3
+
+/* GPIO Control 1 (0x00c0) */
+#define RT5659_GP1_PIN_MASK			(0x1 << 15)
+#define RT5659_GP1_PIN_SFT			15
+#define RT5659_GP1_PIN_GPIO1			(0x0 << 15)
+#define RT5659_GP1_PIN_IRQ			(0x1 << 15)
+#define RT5659_GP2_PIN_MASK			(0x1 << 14)
+#define RT5659_GP2_PIN_SFT			14
+#define RT5659_GP2_PIN_GPIO2			(0x0 << 14)
+#define RT5659_GP2_PIN_DMIC1_SCL		(0x1 << 14)
+#define RT5659_GP3_PIN_MASK			(0x1 << 13)
+#define RT5659_GP3_PIN_SFT			13
+#define RT5659_GP3_PIN_GPIO3			(0x0 << 13)
+#define RT5659_GP3_PIN_PDM_SCL			(0x1 << 13)
+#define RT5659_GP4_PIN_MASK			(0x1 << 12)
+#define RT5659_GP4_PIN_SFT			12
+#define RT5659_GP4_PIN_GPIO4			(0x0 << 12)
+#define RT5659_GP4_PIN_PDM_SDA			(0x1 << 12)
+#define RT5659_GP5_PIN_MASK			(0x1 << 11)
+#define RT5659_GP5_PIN_SFT			11
+#define RT5659_GP5_PIN_GPIO5			(0x0 << 11)
+#define RT5659_GP5_PIN_DMIC1_SDA		(0x1 << 11)
+#define RT5659_GP6_PIN_MASK			(0x1 << 10)
+#define RT5659_GP6_PIN_SFT			10
+#define RT5659_GP6_PIN_GPIO6			(0x0 << 10)
+#define RT5659_GP6_PIN_DMIC2_SDA		(0x1 << 10)
+#define RT5659_GP7_PIN_MASK			(0x1 << 9)
+#define RT5659_GP7_PIN_SFT			9
+#define RT5659_GP7_PIN_GPIO7			(0x0 << 9)
+#define RT5659_GP7_PIN_PDM_SCL			(0x1 << 9)
+#define RT5659_GP8_PIN_MASK			(0x1 << 8)
+#define RT5659_GP8_PIN_SFT			8
+#define RT5659_GP8_PIN_GPIO8			(0x0 << 8)
+#define RT5659_GP8_PIN_PDM_SDA			(0x1 << 8)
+#define RT5659_GP9_PIN_MASK			(0x1 << 7)
+#define RT5659_GP9_PIN_SFT			7
+#define RT5659_GP9_PIN_GPIO9			(0x0 << 7)
+#define RT5659_GP9_PIN_DMIC1_SDA		(0x1 << 7)
+#define RT5659_GP10_PIN_MASK			(0x1 << 6)
+#define RT5659_GP10_PIN_SFT			6
+#define RT5659_GP10_PIN_GPIO10			(0x0 << 6)
+#define RT5659_GP10_PIN_DMIC2_SDA		(0x1 << 6)
+#define RT5659_GP11_PIN_MASK			(0x1 << 5)
+#define RT5659_GP11_PIN_SFT			5
+#define RT5659_GP11_PIN_GPIO11			(0x0 << 5)
+#define RT5659_GP11_PIN_DMIC1_SDA		(0x1 << 5)
+#define RT5659_GP12_PIN_MASK			(0x1 << 4)
+#define RT5659_GP12_PIN_SFT			4
+#define RT5659_GP12_PIN_GPIO12			(0x0 << 4)
+#define RT5659_GP12_PIN_DMIC2_SDA		(0x1 << 4)
+#define RT5659_GP13_PIN_MASK			(0x3 << 2)
+#define RT5659_GP13_PIN_SFT			2
+#define RT5659_GP13_PIN_GPIO13			(0x0 << 2)
+#define RT5659_GP13_PIN_SPDIF_SDA		(0x1 << 2)
+#define RT5659_GP13_PIN_DMIC2_SCL		(0x2 << 2)
+#define RT5659_GP13_PIN_PDM_SCL			(0x3 << 2)
+#define RT5659_GP15_PIN_MASK			(0x3)
+#define RT5659_GP15_PIN_SFT			0
+#define RT5659_GP15_PIN_GPIO15			(0x0)
+#define RT5659_GP15_PIN_DMIC3_SCL		(0x1)
+#define RT5659_GP15_PIN_PDM_SDA			(0x2)
+
+/* GPIO Control 2 (0x00c1)*/
+#define RT5659_GP1_PF_IN			(0x0 << 2)
+#define RT5659_GP1_PF_OUT			(0x1 << 2)
+#define RT5659_GP1_PF_MASK			(0x1 << 2)
+#define RT5659_GP1_PF_SFT			2
+
+/* GPIO Control 3 (0x00c2) */
+#define RT5659_I2S2_PIN_MASK			(0x1 << 15)
+#define RT5659_I2S2_PIN_SFT			15
+#define RT5659_I2S2_PIN_I2S			(0x0 << 15)
+#define RT5659_I2S2_PIN_GPIO			(0x1 << 15)
+
+/* Soft volume and zero cross control 1 (0x00d9) */
+#define RT5659_SV_MASK				(0x1 << 15)
+#define RT5659_SV_SFT				15
+#define RT5659_SV_DIS				(0x0 << 15)
+#define RT5659_SV_EN				(0x1 << 15)
+#define RT5659_OUT_SV_MASK			(0x1 << 13)
+#define RT5659_OUT_SV_SFT			13
+#define RT5659_OUT_SV_DIS			(0x0 << 13)
+#define RT5659_OUT_SV_EN			(0x1 << 13)
+#define RT5659_HP_SV_MASK			(0x1 << 12)
+#define RT5659_HP_SV_SFT			12
+#define RT5659_HP_SV_DIS			(0x0 << 12)
+#define RT5659_HP_SV_EN				(0x1 << 12)
+#define RT5659_ZCD_DIG_MASK			(0x1 << 11)
+#define RT5659_ZCD_DIG_SFT			11
+#define RT5659_ZCD_DIG_DIS			(0x0 << 11)
+#define RT5659_ZCD_DIG_EN			(0x1 << 11)
+#define RT5659_ZCD_MASK				(0x1 << 10)
+#define RT5659_ZCD_SFT				10
+#define RT5659_ZCD_PD				(0x0 << 10)
+#define RT5659_ZCD_PU				(0x1 << 10)
+#define RT5659_SV_DLY_MASK			(0xf)
+#define RT5659_SV_DLY_SFT			0
+
+/* Soft volume and zero cross control 2 (0x00da) */
+#define RT5659_ZCD_HP_MASK			(0x1 << 15)
+#define RT5659_ZCD_HP_SFT			15
+#define RT5659_ZCD_HP_DIS			(0x0 << 15)
+#define RT5659_ZCD_HP_EN			(0x1 << 15)
+
+/* 4 Button Inline Command Control 2 (0x00e0) */
+#define RT5659_4BTN_IL_MASK			(0x1 << 15)
+#define RT5659_4BTN_IL_EN			(0x1 << 15)
+#define RT5659_4BTN_IL_DIS			(0x0 << 15)
+
+/* Analog JD Control 1 (0x00f0) */
+#define RT5659_JD1_MODE_MASK			(0x3 << 0)
+#define RT5659_JD1_MODE_0			(0x0 << 0)
+#define RT5659_JD1_MODE_1			(0x1 << 0)
+#define RT5659_JD1_MODE_2			(0x2 << 0)
+
+/* Jack Detect Control 3 (0x00f8) */
+#define RT5659_JD_TRI_HPO_SEL_MASK		(0x7)
+#define RT5659_JD_TRI_HPO_SEL_SFT		(0)
+#define RT5659_JD_HPO_GPIO_JD1			(0x0)
+#define RT5659_JD_HPO_JD1_1			(0x1)
+#define RT5659_JD_HPO_JD1_2			(0x2)
+#define RT5659_JD_HPO_JD2			(0x3)
+#define RT5659_JD_HPO_GPIO_JD2			(0x4)
+#define RT5659_JD_HPO_JD3			(0x5)
+#define RT5659_JD_HPO_JD_D			(0x6)
+
+/* Digital Misc Control (0x00fa) */
+#define RT5659_AM_MASK				(0x1 << 7)
+#define RT5659_AM_EN				(0x1 << 7)
+#define RT5659_AM_DIS				(0x1 << 7)
+#define RT5659_DIG_GATE_CTRL			0x1
+#define RT5659_DIG_GATE_CTRL_SFT		(0)
+
+/* Chopper and Clock control for ADC (0x011c)*/
+#define RT5659_M_RF_DIG_MASK			(0x1 << 12)
+#define RT5659_M_RF_DIG_SFT			12
+#define RT5659_M_RI_DIG				(0x1 << 11)
+
+/* Chopper and Clock control for DAC (0x013a)*/
+#define RT5659_CKXEN_DAC1_MASK			(0x1 << 13)
+#define RT5659_CKXEN_DAC1_SFT			13
+#define RT5659_CKGEN_DAC1_MASK			(0x1 << 12)
+#define RT5659_CKGEN_DAC1_SFT			12
+#define RT5659_CKXEN_DAC2_MASK			(0x1 << 5)
+#define RT5659_CKXEN_DAC2_SFT			5
+#define RT5659_CKGEN_DAC2_MASK			(0x1 << 4)
+#define RT5659_CKGEN_DAC2_SFT			4
+
+/* Chopper and Clock control for ADC (0x013b)*/
+#define RT5659_CKXEN_ADCC_MASK			(0x1 << 13)
+#define RT5659_CKXEN_ADCC_SFT			13
+#define RT5659_CKGEN_ADCC_MASK			(0x1 << 12)
+#define RT5659_CKGEN_ADCC_SFT			12
+
+/* Test Mode Control 1 (0x0145) */
+#define RT5659_AD2DA_LB_MASK			(0x1 << 9)
+#define RT5659_AD2DA_LB_SFT			9
+
+/* Stereo Noise Gate Control 1 (0x0160) */
+#define RT5659_NG2_EN_MASK			(0x1 << 15)
+#define RT5659_NG2_EN				(0x1 << 15)
+#define RT5659_NG2_DIS				(0x0 << 15)
+
+/* System Clock Source */
+enum {
+	RT5659_SCLK_S_MCLK,
+	RT5659_SCLK_S_PLL1,
+	RT5659_SCLK_S_RCCLK,
+};
+
+/* PLL1 Source */
+enum {
+	RT5659_PLL1_S_MCLK,
+	RT5659_PLL1_S_BCLK1,
+	RT5659_PLL1_S_BCLK2,
+	RT5659_PLL1_S_BCLK3,
+	RT5659_PLL1_S_BCLK4,
+};
+
+enum {
+	RT5659_AIF1,
+	RT5659_AIF2,
+	RT5659_AIF3,
+	RT5659_AIF4,
+	RT5659_AIFS,
+};
+
+struct rt5659_pll_code {
+	bool m_bp;
+	int m_code;
+	int n_code;
+	int k_code;
+};
+
+struct rt5659_priv {
+	struct snd_soc_codec *codec;
+	struct rt5659_platform_data pdata;
+	struct regmap *regmap;
+	struct i2c_client *i2c;
+	struct gpio_desc *gpiod_ldo1_en;
+	struct gpio_desc *gpiod_reset;
+	struct snd_soc_jack *hs_jack;
+	struct delayed_work jack_detect_work;
+
+	int sysclk;
+	int sysclk_src;
+	int lrck[RT5659_AIFS];
+	int bclk[RT5659_AIFS];
+	int master[RT5659_AIFS];
+	int v_id;
+
+	int pll_src;
+	int pll_in;
+	int pll_out;
+
+	int jack_type;
+
+};
+
+int rt5659_set_jack_detect(struct snd_soc_codec *codec,
+	struct snd_soc_jack *hs_jack);
+
+#endif /* __RT5659_H__ */
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 69d987a..33e290b 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -297,8 +297,6 @@
 	case RT5677_HAP_GENE_CTRL2:
 	case RT5677_PWR_DSP_ST:
 	case RT5677_PRIV_DATA:
-	case RT5677_PLL1_CTRL2:
-	case RT5677_PLL2_CTRL2:
 	case RT5677_ASRC_22:
 	case RT5677_ASRC_23:
 	case RT5677_VAD_CTRL5:
@@ -4696,7 +4694,7 @@
 
 	rt5677->gpio_chip = rt5677_template_chip;
 	rt5677->gpio_chip.ngpio = RT5677_GPIO_NUM;
-	rt5677->gpio_chip.dev = &i2c->dev;
+	rt5677->gpio_chip.parent = &i2c->dev;
 	rt5677->gpio_chip.base = -1;
 
 	ret = gpiochip_add(&rt5677->gpio_chip);
@@ -4788,7 +4786,7 @@
 
 	regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
 	gpiod_set_value_cansleep(rt5677->pow_ldo2, 0);
-	gpiod_set_value_cansleep(rt5677->reset_pin, 0);
+	gpiod_set_value_cansleep(rt5677->reset_pin, 1);
 
 	return 0;
 }
@@ -4803,7 +4801,7 @@
 		regcache_mark_dirty(rt5677->regmap);
 
 		gpiod_set_value_cansleep(rt5677->pow_ldo2, 0);
-		gpiod_set_value_cansleep(rt5677->reset_pin, 0);
+		gpiod_set_value_cansleep(rt5677->reset_pin, 1);
 	}
 
 	return 0;
@@ -4814,8 +4812,11 @@
 	struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
 	if (!rt5677->dsp_vad_en) {
+		rt5677->pll_src = 0;
+		rt5677->pll_in = 0;
+		rt5677->pll_out = 0;
 		gpiod_set_value_cansleep(rt5677->pow_ldo2, 1);
-		gpiod_set_value_cansleep(rt5677->reset_pin, 1);
+		gpiod_set_value_cansleep(rt5677->reset_pin, 0);
 		if (rt5677->pow_ldo2 || rt5677->reset_pin)
 			msleep(10);
 
@@ -5160,7 +5161,7 @@
 		return ret;
 	}
 	rt5677->reset_pin = devm_gpiod_get_optional(&i2c->dev,
-			"realtek,reset", GPIOD_OUT_HIGH);
+			"realtek,reset", GPIOD_OUT_LOW);
 	if (IS_ERR(rt5677->reset_pin)) {
 		ret = PTR_ERR(rt5677->reset_pin);
 		dev_err(&i2c->dev, "Failed to request RESET: %d\n", ret);
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index 86b81a6..e2e0bfa 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -309,7 +309,7 @@
 	.count = ARRAY_SIZE(ssm2518_rates_12288000),
 };
 
-static unsigned int ssm2518_lookup_mcs(struct ssm2518 *ssm2518,
+static int ssm2518_lookup_mcs(struct ssm2518 *ssm2518,
 	unsigned int rate)
 {
 	const unsigned int *sysclks = NULL;
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 4cad892..bc3de2e 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -1097,8 +1097,7 @@
 {
 	struct twl6040_data *priv;
 	struct twl6040 *twl6040 = dev_get_drvdata(codec->dev->parent);
-	struct platform_device *pdev = container_of(codec->dev,
-						   struct platform_device, dev);
+	struct platform_device *pdev = to_platform_device(codec->dev);
 	int ret = 0;
 
 	priv = devm_kzalloc(codec->dev, sizeof(*priv), GFP_KERNEL);
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index c2cdcae..171a23d 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -2306,7 +2306,7 @@
 
 	wm5100->gpio_chip = wm5100_template_chip;
 	wm5100->gpio_chip.ngpio = 6;
-	wm5100->gpio_chip.dev = &i2c->dev;
+	wm5100->gpio_chip.parent = &i2c->dev;
 
 	if (wm5100->pdata.gpio_base)
 		wm5100->gpio_chip.base = wm5100->pdata.gpio_base;
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index c04c0bc..6088d30 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -360,15 +360,13 @@
 
 static int wm5110_clear_pga_volume(struct arizona *arizona, int output)
 {
-	struct reg_sequence clear_pga = {
-		ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4, 0x80
-	};
+	unsigned int reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4;
 	int ret;
 
-	ret = regmap_multi_reg_write_bypassed(arizona->regmap, &clear_pga, 1);
+	ret = regmap_write(arizona->regmap, reg, 0x80);
 	if (ret)
 		dev_err(arizona->dev, "Failed to clear PGA (0x%x): %d\n",
-			clear_pga.reg, ret);
+			reg, ret);
 
 	return ret;
 }
@@ -439,18 +437,17 @@
 {
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct snd_soc_card *card = dapm->card;
 	int ret;
 
 	/*
 	 * PGA Volume is also used as part of the enable sequence, so
 	 * usage of it should be avoided whilst that is running.
 	 */
-	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+	snd_soc_dapm_mutex_lock(dapm);
 
 	ret = snd_soc_get_volsw_range(kcontrol, ucontrol);
 
-	mutex_unlock(&card->dapm_mutex);
+	snd_soc_dapm_mutex_unlock(dapm);
 
 	return ret;
 }
@@ -460,18 +457,17 @@
 {
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct snd_soc_card *card = dapm->card;
 	int ret;
 
 	/*
 	 * PGA Volume is also used as part of the enable sequence, so
 	 * usage of it should be avoided whilst that is running.
 	 */
-	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+	snd_soc_dapm_mutex_lock(dapm);
 
 	ret = snd_soc_put_volsw_range(kcontrol, ucontrol);
 
-	mutex_unlock(&card->dapm_mutex);
+	snd_soc_dapm_mutex_unlock(dapm);
 
 	return ret;
 }
@@ -575,6 +571,33 @@
 	SOC_SINGLE(name " NG SPKDAT2L Switch", base, 10, 1, 0), \
 	SOC_SINGLE(name " NG SPKDAT2R Switch", base, 11, 1, 0)
 
+#define WM5110_RXANC_INPUT_ROUTES(widget, name) \
+	{ widget, NULL, name " NG Mux" }, \
+	{ name " NG Internal", NULL, "RXANC NG Clock" }, \
+	{ name " NG Internal", NULL, name " Channel" }, \
+	{ name " NG External", NULL, "RXANC NG External Clock" }, \
+	{ name " NG External", NULL, name " Channel" }, \
+	{ name " NG Mux", "None", name " Channel" }, \
+	{ name " NG Mux", "Internal", name " NG Internal" }, \
+	{ name " NG Mux", "External", name " NG External" }, \
+	{ name " Channel", "Left", name " Left Input" }, \
+	{ name " Channel", "Combine", name " Left Input" }, \
+	{ name " Channel", "Right", name " Right Input" }, \
+	{ name " Channel", "Combine", name " Right Input" }, \
+	{ name " Left Input", "IN1", "IN1L PGA" }, \
+	{ name " Right Input", "IN1", "IN1R PGA" }, \
+	{ name " Left Input", "IN2", "IN2L PGA" }, \
+	{ name " Right Input", "IN2", "IN2R PGA" }, \
+	{ name " Left Input", "IN3", "IN3L PGA" }, \
+	{ name " Right Input", "IN3", "IN3R PGA" }, \
+	{ name " Left Input", "IN4", "IN4L PGA" }, \
+	{ name " Right Input", "IN4", "IN4R PGA" }
+
+#define WM5110_RXANC_OUTPUT_ROUTES(widget, name) \
+	{ widget, NULL, name " ANC Source" }, \
+	{ name " ANC Source", "RXANCL", "RXANCL" }, \
+	{ name " ANC Source", "RXANCR", "RXANCR" }
+
 static const struct snd_kcontrol_new wm5110_snd_controls[] = {
 SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]),
 SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
@@ -639,6 +662,15 @@
 SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
 SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
 
+SND_SOC_BYTES("RXANC Coefficients", ARIZONA_ANC_COEFF_START,
+	      ARIZONA_ANC_COEFF_END - ARIZONA_ANC_COEFF_START + 1),
+SND_SOC_BYTES("RXANCL Config", ARIZONA_FCL_FILTER_CONTROL, 1),
+SND_SOC_BYTES("RXANCL Coefficients", ARIZONA_FCL_COEFF_START,
+	      ARIZONA_FCL_COEFF_END - ARIZONA_FCL_COEFF_START + 1),
+SND_SOC_BYTES("RXANCR Config", ARIZONA_FCR_FILTER_CONTROL, 1),
+SND_SOC_BYTES("RXANCR Coefficients", ARIZONA_FCR_COEFF_START,
+	      ARIZONA_FCR_COEFF_END - ARIZONA_FCR_COEFF_START + 1),
+
 ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
@@ -995,6 +1027,31 @@
 static const struct snd_kcontrol_new wm5110_aec_loopback_mux =
 	SOC_DAPM_ENUM("AEC Loopback", wm5110_aec_loopback);
 
+static const struct snd_kcontrol_new wm5110_anc_input_mux[] = {
+	SOC_DAPM_ENUM("RXANCL Input", arizona_anc_input_src[0]),
+	SOC_DAPM_ENUM("RXANCL Channel", arizona_anc_input_src[1]),
+	SOC_DAPM_ENUM("RXANCR Input", arizona_anc_input_src[2]),
+	SOC_DAPM_ENUM("RXANCR Channel", arizona_anc_input_src[3]),
+};
+
+static const struct snd_kcontrol_new wm5110_anc_ng_mux =
+	SOC_DAPM_ENUM("RXANC NG Source", arizona_anc_ng_enum);
+
+static const struct snd_kcontrol_new wm5110_output_anc_src[] = {
+	SOC_DAPM_ENUM("HPOUT1L ANC Source", arizona_output_anc_src[0]),
+	SOC_DAPM_ENUM("HPOUT1R ANC Source", arizona_output_anc_src[1]),
+	SOC_DAPM_ENUM("HPOUT2L ANC Source", arizona_output_anc_src[2]),
+	SOC_DAPM_ENUM("HPOUT2R ANC Source", arizona_output_anc_src[3]),
+	SOC_DAPM_ENUM("HPOUT3L ANC Source", arizona_output_anc_src[4]),
+	SOC_DAPM_ENUM("HPOUT3R ANC Source", arizona_output_anc_src[5]),
+	SOC_DAPM_ENUM("SPKOUTL ANC Source", arizona_output_anc_src[6]),
+	SOC_DAPM_ENUM("SPKOUTR ANC Source", arizona_output_anc_src[7]),
+	SOC_DAPM_ENUM("SPKDAT1L ANC Source", arizona_output_anc_src[8]),
+	SOC_DAPM_ENUM("SPKDAT1R ANC Source", arizona_output_anc_src[9]),
+	SOC_DAPM_ENUM("SPKDAT2L ANC Source", arizona_output_anc_src[10]),
+	SOC_DAPM_ENUM("SPKDAT2R ANC Source", arizona_output_anc_src[11]),
+};
+
 static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
 		    0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU),
@@ -1185,6 +1242,65 @@
 		       ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
 		       &wm5110_aec_loopback_mux),
 
+SND_SOC_DAPM_SUPPLY("RXANC NG External Clock", SND_SOC_NOPM,
+		   ARIZONA_EXT_NG_SEL_SET_SHIFT, 0, arizona_anc_ev,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA("RXANCL NG External", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("RXANCR NG External", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("RXANC NG Clock", SND_SOC_NOPM,
+		   ARIZONA_CLK_NG_ENA_SET_SHIFT, 0, arizona_anc_ev,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA("RXANCL NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("RXANCR NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("RXANCL Left Input", SND_SOC_NOPM, 0, 0,
+		 &wm5110_anc_input_mux[0]),
+SND_SOC_DAPM_MUX("RXANCL Right Input", SND_SOC_NOPM, 0, 0,
+		 &wm5110_anc_input_mux[0]),
+SND_SOC_DAPM_MUX("RXANCL Channel", SND_SOC_NOPM, 0, 0,
+		 &wm5110_anc_input_mux[1]),
+SND_SOC_DAPM_MUX("RXANCL NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux),
+SND_SOC_DAPM_MUX("RXANCR Left Input", SND_SOC_NOPM, 0, 0,
+		 &wm5110_anc_input_mux[2]),
+SND_SOC_DAPM_MUX("RXANCR Right Input", SND_SOC_NOPM, 0, 0,
+		 &wm5110_anc_input_mux[2]),
+SND_SOC_DAPM_MUX("RXANCR Channel", SND_SOC_NOPM, 0, 0,
+		 &wm5110_anc_input_mux[3]),
+SND_SOC_DAPM_MUX("RXANCR NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux),
+
+SND_SOC_DAPM_PGA_E("RXANCL", SND_SOC_NOPM, ARIZONA_CLK_L_ENA_SET_SHIFT,
+		   0, NULL, 0, arizona_anc_ev,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA_E("RXANCR", SND_SOC_NOPM, ARIZONA_CLK_R_ENA_SET_SHIFT,
+		   0, NULL, 0, arizona_anc_ev,
+		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_MUX("HPOUT1L ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[0]),
+SND_SOC_DAPM_MUX("HPOUT1R ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[1]),
+SND_SOC_DAPM_MUX("HPOUT2L ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[2]),
+SND_SOC_DAPM_MUX("HPOUT2R ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[3]),
+SND_SOC_DAPM_MUX("HPOUT3L ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[4]),
+SND_SOC_DAPM_MUX("HPOUT3R ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[5]),
+SND_SOC_DAPM_MUX("SPKOUTL ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[6]),
+SND_SOC_DAPM_MUX("SPKOUTR ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[7]),
+SND_SOC_DAPM_MUX("SPKDAT1L ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[8]),
+SND_SOC_DAPM_MUX("SPKDAT1R ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[9]),
+SND_SOC_DAPM_MUX("SPKDAT2L ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[10]),
+SND_SOC_DAPM_MUX("SPKDAT2R ANC Source", SND_SOC_NOPM, 0, 0,
+		 &wm5110_output_anc_src[11]),
+
 SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
 		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
 SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
@@ -1690,6 +1806,9 @@
 	{ "Slim2 Capture", NULL, "SYSCLK" },
 	{ "Slim3 Capture", NULL, "SYSCLK" },
 
+	{ "Voice Control DSP", NULL, "DSP3" },
+	{ "Voice Control DSP", NULL, "SYSCLK" },
+
 	{ "IN1L PGA", NULL, "IN1L" },
 	{ "IN1R PGA", NULL, "IN1R" },
 
@@ -1838,6 +1957,22 @@
 	{ "SPKDAT2L", NULL, "OUT6L" },
 	{ "SPKDAT2R", NULL, "OUT6R" },
 
+	WM5110_RXANC_INPUT_ROUTES("RXANCL", "RXANCL"),
+	WM5110_RXANC_INPUT_ROUTES("RXANCR", "RXANCR"),
+
+	WM5110_RXANC_OUTPUT_ROUTES("OUT1L", "HPOUT1L"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT1R", "HPOUT1R"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT2L", "HPOUT2L"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT2R", "HPOUT2R"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT3L", "HPOUT3L"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT3R", "HPOUT3R"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT4L", "SPKOUTL"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT4R", "SPKOUTR"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT5L", "SPKDAT1L"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT5R", "SPKDAT1R"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT6L", "SPKDAT2L"),
+	WM5110_RXANC_OUTPUT_ROUTES("OUT6R", "SPKDAT2R"),
+
 	{ "MICSUPP", NULL, "SYSCLK" },
 
 	{ "DRC1 Signal Activity", NULL, "DRC1L" },
@@ -1996,12 +2131,65 @@
 		 },
 		.ops = &arizona_simple_dai_ops,
 	},
+	{
+		.name = "wm5110-cpu-voicectrl",
+		.capture = {
+			.stream_name = "Voice Control CPU",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = WM5110_RATES,
+			.formats = WM5110_FORMATS,
+		},
+		.compress_new = snd_soc_new_compress,
+	},
+	{
+		.name = "wm5110-dsp-voicectrl",
+		.capture = {
+			.stream_name = "Voice Control DSP",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = WM5110_RATES,
+			.formats = WM5110_FORMATS,
+		},
+	},
 };
 
+static int wm5110_open(struct snd_compr_stream *stream)
+{
+	struct snd_soc_pcm_runtime *rtd = stream->private_data;
+	struct wm5110_priv *priv = snd_soc_codec_get_drvdata(rtd->codec);
+	struct arizona *arizona = priv->core.arizona;
+	int n_adsp;
+
+	if (strcmp(rtd->codec_dai->name, "wm5110-dsp-voicectrl") == 0) {
+		n_adsp = 2;
+	} else {
+		dev_err(arizona->dev,
+			"No suitable compressed stream for DAI '%s'\n",
+			rtd->codec_dai->name);
+		return -EINVAL;
+	}
+
+	return wm_adsp_compr_open(&priv->core.adsp[n_adsp], stream);
+}
+
+static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
+{
+	struct wm5110_priv *florida = data;
+	int ret;
+
+	ret = wm_adsp_compr_handle_irq(&florida->core.adsp[2]);
+	if (ret == -ENODEV)
+		return IRQ_NONE;
+
+	return IRQ_HANDLED;
+}
+
 static int wm5110_codec_probe(struct snd_soc_codec *codec)
 {
 	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 	struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona *arizona = priv->core.arizona;
 	int i, ret;
 
 	priv->core.arizona->dapm = dapm;
@@ -2010,6 +2198,14 @@
 	arizona_init_gpio(codec);
 	arizona_init_mono(codec);
 
+	ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
+				  "ADSP2 Compressed IRQ", wm5110_adsp2_irq,
+				  priv);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret);
+		return ret;
+	}
+
 	for (i = 0; i < WM5110_NUM_ADSP; ++i) {
 		ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec);
 		if (ret)
@@ -2030,12 +2226,15 @@
 	for (--i; i >= 0; --i)
 		wm_adsp2_codec_remove(&priv->core.adsp[i], codec);
 
+	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
+
 	return ret;
 }
 
 static int wm5110_codec_remove(struct snd_soc_codec *codec)
 {
 	struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona *arizona = priv->core.arizona;
 	int i;
 
 	for (i = 0; i < WM5110_NUM_ADSP; ++i)
@@ -2043,6 +2242,8 @@
 
 	priv->core.arizona->dapm = NULL;
 
+	arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
+
 	return 0;
 }
 
@@ -2088,6 +2289,20 @@
 	.num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes),
 };
 
+static struct snd_compr_ops wm5110_compr_ops = {
+	.open = wm5110_open,
+	.free = wm_adsp_compr_free,
+	.set_params = wm_adsp_compr_set_params,
+	.get_caps = wm_adsp_compr_get_caps,
+	.trigger = wm_adsp_compr_trigger,
+	.pointer = wm_adsp_compr_pointer,
+	.copy = wm_adsp_compr_copy,
+};
+
+static struct snd_soc_platform_driver wm5110_compr_platform = {
+	.compr_ops = &wm5110_compr_ops,
+};
+
 static int wm5110_probe(struct platform_device *pdev)
 {
 	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
@@ -2148,8 +2363,21 @@
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_idle(&pdev->dev);
 
-	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
+	ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
+		goto error;
+	}
+
+	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
 				      wm5110_dai, ARRAY_SIZE(wm5110_dai));
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
+		snd_soc_unregister_platform(&pdev->dev);
+	}
+
+error:
+	return ret;
 }
 
 static int wm5110_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index e4cc41e..a82b8bc 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1804,7 +1804,7 @@
 
 	regmap_read(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, &reg);
 
-	return (reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT;
+	return !!((reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT);
 }
 
 static int wm8903_gpio_direction_out(struct gpio_chip *chip,
@@ -1853,7 +1853,7 @@
 
 	wm8903->gpio_chip = wm8903_template_chip;
 	wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO;
-	wm8903->gpio_chip.dev = wm8903->dev;
+	wm8903->gpio_chip.parent = wm8903->dev;
 
 	if (pdata->gpio_base)
 		wm8903->gpio_chip.base = pdata->gpio_base;
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 2aa23f1..8172e49 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -312,7 +312,7 @@
 	case WM8904_FLL_NCO_TEST_1:
 		return true;
 	default:
-		return true;
+		return false;
 	}
 }
 
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 5380798..ff23772 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -147,6 +147,13 @@
 static const char *wm8960_3d_lower_cutoff[] = {"Low", "High"};
 static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"};
 static const char *wm8960_alcmode[] = {"ALC", "Limiter"};
+static const char *wm8960_adc_data_output_sel[] = {
+	"Left Data = Left ADC;  Right Data = Right ADC",
+	"Left Data = Left ADC;  Right Data = Left ADC",
+	"Left Data = Right ADC; Right Data = Right ADC",
+	"Left Data = Right ADC; Right Data = Left ADC",
+};
+static const char *wm8960_dmonomix[] = {"Stereo", "Mono"};
 
 static const struct soc_enum wm8960_enum[] = {
 	SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity),
@@ -155,6 +162,8 @@
 	SOC_ENUM_SINGLE(WM8960_3D, 5, 2, wm8960_3d_lower_cutoff),
 	SOC_ENUM_SINGLE(WM8960_ALC1, 7, 4, wm8960_alcfunc),
 	SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode),
+	SOC_ENUM_SINGLE(WM8960_ADDCTL1, 2, 4, wm8960_adc_data_output_sel),
+	SOC_ENUM_SINGLE(WM8960_ADDCTL1, 4, 2, wm8960_dmonomix),
 };
 
 static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
@@ -295,6 +304,9 @@
 	       WM8960_BYPASS2, 4, 7, 1, bypass_tlv),
 SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume",
 	       WM8960_ROUTMIX, 4, 7, 1, bypass_tlv),
+
+SOC_ENUM("ADC Data Output Select", wm8960_enum[6]),
+SOC_ENUM("DAC Mono Mix", wm8960_enum[7]),
 };
 
 static const struct snd_kcontrol_new wm8960_lin_boost[] = {
@@ -401,8 +413,8 @@
 	{ "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" },
 	{ "Left Boost Mixer", "LINPUT3 Switch", "LINPUT3" },
 
-	{ "Left Input Mixer", "Boost Switch", "Left Boost Mixer", },
-	{ "Left Input Mixer", NULL, "LINPUT1", },  /* Really Boost Switch */
+	{ "Left Input Mixer", "Boost Switch", "Left Boost Mixer" },
+	{ "Left Input Mixer", "Boost Switch", "LINPUT1" },  /* Really Boost Switch */
 	{ "Left Input Mixer", NULL, "LINPUT2" },
 	{ "Left Input Mixer", NULL, "LINPUT3" },
 
@@ -410,8 +422,8 @@
 	{ "Right Boost Mixer", "RINPUT2 Switch", "RINPUT2" },
 	{ "Right Boost Mixer", "RINPUT3 Switch", "RINPUT3" },
 
-	{ "Right Input Mixer", "Boost Switch", "Right Boost Mixer", },
-	{ "Right Input Mixer", NULL, "RINPUT1", },  /* Really Boost Switch */
+	{ "Right Input Mixer", "Boost Switch", "Right Boost Mixer" },
+	{ "Right Input Mixer", "Boost Switch", "RINPUT1" },  /* Really Boost Switch */
 	{ "Right Input Mixer", NULL, "RINPUT2" },
 	{ "Right Input Mixer", NULL, "RINPUT3" },
 
@@ -419,11 +431,11 @@
 	{ "Right ADC", NULL, "Right Input Mixer" },
 
 	{ "Left Output Mixer", "LINPUT3 Switch", "LINPUT3" },
-	{ "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer"} ,
+	{ "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer" },
 	{ "Left Output Mixer", "PCM Playback Switch", "Left DAC" },
 
 	{ "Right Output Mixer", "RINPUT3 Switch", "RINPUT3" },
-	{ "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" } ,
+	{ "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" },
 	{ "Right Output Mixer", "PCM Playback Switch", "Right DAC" },
 
 	{ "LOUT1 PGA", NULL, "Left Output Mixer" },
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index a7e7978..8822360 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -131,7 +131,7 @@
 	{ 15, 0x6243 },   /* R15    - Software Reset */
 
 	{ 17, 0x007B },   /* R17    - ALC1 */
-
+	{ 18, 0x0000 },   /* R18    - ALC2 */
 	{ 19, 0x1C32 },   /* R19    - ALC3 */
 	{ 20, 0x3200 },   /* R20    - Noise Gate */
 	{ 21, 0x00C0 },   /* R21    - Left ADC volume */
@@ -794,7 +794,6 @@
 	case WM8962_CLOCKING1:
 	case WM8962_CLOCKING2:
 	case WM8962_SOFTWARE_RESET:
-	case WM8962_ALC2:
 	case WM8962_THERMAL_SHUTDOWN_STATUS:
 	case WM8962_ADDITIONAL_CONTROL_4:
 	case WM8962_DC_SERVO_6:
@@ -3380,7 +3379,7 @@
 
 	wm8962->gpio_chip = wm8962_template_chip;
 	wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO;
-	wm8962->gpio_chip.dev = codec->dev;
+	wm8962->gpio_chip.parent = codec->dev;
 
 	if (pdata->gpio_base)
 		wm8962->gpio_chip.base = pdata->gpio_base;
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 4c29bd2..c284c7b 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -632,9 +632,16 @@
 };
 MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id);
 
+static const struct of_device_id wm8974_of_match[] = {
+       { .compatible = "wlf,wm8974", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wm8974_of_match);
+
 static struct i2c_driver wm8974_i2c_driver = {
 	.driver = {
 		.name = "wm8974",
+		.of_match_table = wm8974_of_match,
 	},
 	.probe =    wm8974_i2c_probe,
 	.remove =   wm8974_i2c_remove,
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index f7ccd9f..8d7d6c0 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -2204,7 +2204,7 @@
 
 	wm8996->gpio_chip = wm8996_template_chip;
 	wm8996->gpio_chip.ngpio = 5;
-	wm8996->gpio_chip.dev = wm8996->dev;
+	wm8996->gpio_chip.parent = wm8996->dev;
 
 	if (wm8996->pdata.gpio_base)
 		wm8996->gpio_chip.base = wm8996->pdata.gpio_base;
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c
index 8782dfb..7719bc5 100644
--- a/sound/soc/codecs/wm8998.c
+++ b/sound/soc/codecs/wm8998.c
@@ -199,20 +199,20 @@
 	"B",
 };
 
-static const SOC_ENUM_SINGLE_DECL(wm8998_in1muxl_enum,
-				  ARIZONA_ADC_DIGITAL_VOLUME_1L,
-				  ARIZONA_IN1L_SRC_SHIFT,
-				  wm8998_inmux_texts);
+static SOC_ENUM_SINGLE_DECL(wm8998_in1muxl_enum,
+			    ARIZONA_ADC_DIGITAL_VOLUME_1L,
+			    ARIZONA_IN1L_SRC_SHIFT,
+			    wm8998_inmux_texts);
 
-static const SOC_ENUM_SINGLE_DECL(wm8998_in1muxr_enum,
-				  ARIZONA_ADC_DIGITAL_VOLUME_1R,
-				  ARIZONA_IN1R_SRC_SHIFT,
-				  wm8998_inmux_texts);
+static SOC_ENUM_SINGLE_DECL(wm8998_in1muxr_enum,
+			    ARIZONA_ADC_DIGITAL_VOLUME_1R,
+			    ARIZONA_IN1R_SRC_SHIFT,
+			    wm8998_inmux_texts);
 
-static const SOC_ENUM_SINGLE_DECL(wm8998_in2mux_enum,
-				  ARIZONA_ADC_DIGITAL_VOLUME_2L,
-				  ARIZONA_IN2L_SRC_SHIFT,
-				  wm8998_inmux_texts);
+static SOC_ENUM_SINGLE_DECL(wm8998_in2mux_enum,
+			    ARIZONA_ADC_DIGITAL_VOLUME_2L,
+			    ARIZONA_IN2L_SRC_SHIFT,
+			    wm8998_inmux_texts);
 
 static const struct snd_kcontrol_new wm8998_in1mux[2] = {
 	SOC_DAPM_ENUM_EXT("IN1L Mux", wm8998_in1muxl_enum,
@@ -522,17 +522,17 @@
 	0, 1, 2, 3, 4, 6, 7, 8, 9,
 };
 
-static const SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec1_loopback,
-					ARIZONA_DAC_AEC_CONTROL_1,
-					ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
-					wm8998_aec_loopback_texts,
-					wm8998_aec_loopback_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec1_loopback,
+				  ARIZONA_DAC_AEC_CONTROL_1,
+				  ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+				  wm8998_aec_loopback_texts,
+				  wm8998_aec_loopback_values);
 
-static const SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec2_loopback,
-					ARIZONA_DAC_AEC_CONTROL_2,
-					ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
-					wm8998_aec_loopback_texts,
-					wm8998_aec_loopback_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec2_loopback,
+				  ARIZONA_DAC_AEC_CONTROL_2,
+				  ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+				  wm8998_aec_loopback_texts,
+				  wm8998_aec_loopback_values);
 
 static const struct snd_kcontrol_new wm8998_aec_loopback_mux[] = {
 	SOC_DAPM_ENUM("AEC1 Loopback", wm8998_aec1_loopback),
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 4083a51..79e1436 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -19,6 +19,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/regmap.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
@@ -39,34 +40,6 @@
 	struct mutex lock;
 };
 
-static unsigned int ac97_read(struct snd_soc_codec *codec,
-	unsigned int reg);
-static int ac97_write(struct snd_soc_codec *codec,
-	unsigned int reg, unsigned int val);
-
-/*
- * WM9713 register cache
- * Reg 0x3c bit 15 is used by touch driver.
- */
-static const u16 wm9713_reg[] = {
-	0x6174, 0x8080, 0x8080, 0x8080,
-	0xc880, 0xe808, 0xe808, 0x0808,
-	0x00da, 0x8000, 0xd600, 0xaaa0,
-	0xaaa0, 0xaaa0, 0x0000, 0x0000,
-	0x0f0f, 0x0040, 0x0000, 0x7f00,
-	0x0405, 0x0410, 0xbb80, 0xbb80,
-	0x0000, 0xbb80, 0x0000, 0x4523,
-	0x0000, 0x2000, 0x7eff, 0xffff,
-	0x0000, 0x0000, 0x0080, 0x0000,
-	0x0000, 0x0000, 0xfffe, 0xffff,
-	0x0000, 0x0000, 0x0000, 0xfffe,
-	0x4000, 0x0000, 0x0000, 0x0000,
-	0xb032, 0x3e00, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000, 0x0006,
-	0x0001, 0x0000, 0x574d, 0x4c13,
-};
-
 #define HPL_MIXER 0
 #define HPR_MIXER 1
 
@@ -220,18 +193,15 @@
 				 struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	u16 status, rate;
 
 	if (WARN_ON(event != SND_SOC_DAPM_PRE_PMD))
 		return -EINVAL;
 
 	/* Gracefully shut down the voice interface. */
-	status = ac97_read(codec, AC97_EXTENDED_MID) | 0x1000;
-	rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF;
-	ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200);
+	snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, 0x0200);
 	schedule_timeout_interruptible(msecs_to_jiffies(1));
-	ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00);
-	ac97_write(codec, AC97_EXTENDED_MID, status);
+	snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, 0x0f00);
+	snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x1000, 0x1000);
 
 	return 0;
 }
@@ -674,40 +644,98 @@
 	{"Capture Mono Mux", "Right", "Right Capture Source"},
 };
 
-static unsigned int ac97_read(struct snd_soc_codec *codec,
-	unsigned int reg)
+static bool wm9713_readable_reg(struct device *dev, unsigned int reg)
 {
-	struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
-	u16 *cache = codec->reg_cache;
-
-	if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
-		reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||
-		reg == AC97_CD)
-		return soc_ac97_ops->read(wm9713->ac97, reg);
-	else {
-		reg = reg >> 1;
-
-		if (reg >= (ARRAY_SIZE(wm9713_reg)))
-			return -EIO;
-
-		return cache[reg];
+	switch (reg) {
+	case AC97_RESET ... AC97_PCM_SURR_DAC_RATE:
+	case AC97_PCM_LR_ADC_RATE:
+	case AC97_CENTER_LFE_MASTER:
+	case AC97_SPDIF ... AC97_LINE1_LEVEL:
+	case AC97_GPIO_CFG ... 0x5c:
+	case AC97_CODEC_CLASS_REV ... AC97_PCI_SID:
+	case 0x74 ... AC97_VENDOR_ID2:
+		return true;
+	default:
+		return false;
 	}
 }
 
-static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int val)
+static bool wm9713_writeable_reg(struct device *dev, unsigned int reg)
 {
-	struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
-
-	u16 *cache = codec->reg_cache;
-	soc_ac97_ops->write(wm9713->ac97, reg, val);
-	reg = reg >> 1;
-	if (reg < (ARRAY_SIZE(wm9713_reg)))
-		cache[reg] = val;
-
-	return 0;
+	switch (reg) {
+	case AC97_VENDOR_ID1:
+	case AC97_VENDOR_ID2:
+		return false;
+	default:
+		return wm9713_readable_reg(dev, reg);
+	}
 }
 
+static const struct reg_default wm9713_reg_defaults[] = {
+	{ 0x02, 0x8080 },	/* Speaker Output Volume */
+	{ 0x04, 0x8080 },	/* Headphone Output Volume */
+	{ 0x06, 0x8080 },	/* Out3/OUT4 Volume */
+	{ 0x08, 0xc880 },	/* Mono Volume */
+	{ 0x0a, 0xe808 },	/* LINEIN Volume */
+	{ 0x0c, 0xe808 },	/* DAC PGA Volume */
+	{ 0x0e, 0x0808 },	/* MIC PGA Volume */
+	{ 0x10, 0x00da },	/* MIC Routing Control */
+	{ 0x12, 0x8000 },	/* Record PGA Volume */
+	{ 0x14, 0xd600 },	/* Record Routing */
+	{ 0x16, 0xaaa0 },	/* PCBEEP Volume */
+	{ 0x18, 0xaaa0 },	/* VxDAC Volume */
+	{ 0x1a, 0xaaa0 },	/* AUXDAC Volume */
+	{ 0x1c, 0x0000 },	/* Output PGA Mux */
+	{ 0x1e, 0x0000 },	/* DAC 3D control */
+	{ 0x20, 0x0f0f },	/* DAC Tone Control*/
+	{ 0x22, 0x0040 },	/* MIC Input Select & Bias */
+	{ 0x24, 0x0000 },	/* Output Volume Mapping & Jack */
+	{ 0x26, 0x7f00 },	/* Powerdown Ctrl/Stat*/
+	{ 0x28, 0x0405 },	/* Extended Audio ID */
+	{ 0x2a, 0x0410 },	/* Extended Audio Start/Ctrl */
+	{ 0x2c, 0xbb80 },	/* Audio DACs Sample Rate */
+	{ 0x2e, 0xbb80 },	/* AUXDAC Sample Rate */
+	{ 0x32, 0xbb80 },	/* Audio ADCs Sample Rate */
+	{ 0x36, 0x4523 },	/* PCM codec control */
+	{ 0x3a, 0x2000 },	/* SPDIF control */
+	{ 0x3c, 0xfdff },	/* Powerdown 1 */
+	{ 0x3e, 0xffff },	/* Powerdown 2 */
+	{ 0x40, 0x0000 },	/* General Purpose */
+	{ 0x42, 0x0000 },	/* Fast Power-Up Control */
+	{ 0x44, 0x0080 },	/* MCLK/PLL Control */
+	{ 0x46, 0x0000 },	/* MCLK/PLL Control */
+	{ 0x4c, 0xfffe },	/* GPIO Pin Configuration */
+	{ 0x4e, 0xffff },	/* GPIO Pin Polarity / Type */
+	{ 0x50, 0x0000 },	/* GPIO Pin Sticky */
+	{ 0x52, 0x0000 },	/* GPIO Pin Wake-Up */
+				/* GPIO Pin Status */
+	{ 0x56, 0xfffe },	/* GPIO Pin Sharing */
+	{ 0x58, 0x4000 },	/* GPIO PullUp/PullDown */
+	{ 0x5a, 0x0000 },	/* Additional Functions 1 */
+	{ 0x5c, 0x0000 },	/* Additional Functions 2 */
+	{ 0x60, 0xb032 },	/* ALC Control */
+	{ 0x62, 0x3e00 },	/* ALC / Noise Gate Control */
+	{ 0x64, 0x0000 },	/* AUXDAC input control */
+	{ 0x74, 0x0000 },	/* Digitiser Reg 1 */
+	{ 0x76, 0x0006 },	/* Digitiser Reg 2 */
+	{ 0x78, 0x0001 },	/* Digitiser Reg 3 */
+	{ 0x7a, 0x0000 },	/* Digitiser Read Back */
+};
+
+static const struct regmap_config wm9713_regmap_config = {
+	.reg_bits = 16,
+	.reg_stride = 2,
+	.val_bits = 16,
+	.max_register = 0x7e,
+	.cache_type = REGCACHE_RBTREE,
+
+	.reg_defaults = wm9713_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(wm9713_reg_defaults),
+	.volatile_reg = regmap_ac97_default_volatile,
+	.readable_reg = wm9713_readable_reg,
+	.writeable_reg = wm9713_writeable_reg,
+};
+
 /* PLL divisors */
 struct _pll_div {
 	u32 divsel:1;
@@ -793,10 +821,8 @@
 	/* turn PLL off ? */
 	if (freq_in == 0) {
 		/* disable PLL power and select ext source */
-		reg = ac97_read(codec, AC97_HANDSET_RATE);
-		ac97_write(codec, AC97_HANDSET_RATE, reg | 0x0080);
-		reg = ac97_read(codec, AC97_EXTENDED_MID);
-		ac97_write(codec, AC97_EXTENDED_MID, reg | 0x0200);
+		snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0080, 0x0080);
+		snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x0200, 0x0200);
 		wm9713->pll_in = 0;
 		return 0;
 	}
@@ -806,7 +832,7 @@
 	if (pll_div.k == 0) {
 		reg = (pll_div.n << 12) | (pll_div.lf << 11) |
 			(pll_div.divsel << 9) | (pll_div.divctl << 8);
-		ac97_write(codec, AC97_LINE1_LEVEL, reg);
+		snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
 	} else {
 		/* write the fractional k to the reg 0x46 pages */
 		reg2 = (pll_div.n << 12) | (pll_div.lf << 11) | (1 << 10) |
@@ -814,33 +840,31 @@
 
 		/* K [21:20] */
 		reg = reg2 | (0x5 << 4) | (pll_div.k >> 20);
-		ac97_write(codec, AC97_LINE1_LEVEL, reg);
+		snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
 
 		/* K [19:16] */
 		reg = reg2 | (0x4 << 4) | ((pll_div.k >> 16) & 0xf);
-		ac97_write(codec, AC97_LINE1_LEVEL, reg);
+		snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
 
 		/* K [15:12] */
 		reg = reg2 | (0x3 << 4) | ((pll_div.k >> 12) & 0xf);
-		ac97_write(codec, AC97_LINE1_LEVEL, reg);
+		snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
 
 		/* K [11:8] */
 		reg = reg2 | (0x2 << 4) | ((pll_div.k >> 8) & 0xf);
-		ac97_write(codec, AC97_LINE1_LEVEL, reg);
+		snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
 
 		/* K [7:4] */
 		reg = reg2 | (0x1 << 4) | ((pll_div.k >> 4) & 0xf);
-		ac97_write(codec, AC97_LINE1_LEVEL, reg);
+		snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
 
 		reg = reg2 | (0x0 << 4) | (pll_div.k & 0xf); /* K [3:0] */
-		ac97_write(codec, AC97_LINE1_LEVEL, reg);
+		snd_soc_write(codec, AC97_LINE1_LEVEL, reg);
 	}
 
 	/* turn PLL on and select as source */
-	reg = ac97_read(codec, AC97_EXTENDED_MID);
-	ac97_write(codec, AC97_EXTENDED_MID, reg & 0xfdff);
-	reg = ac97_read(codec, AC97_HANDSET_RATE);
-	ac97_write(codec, AC97_HANDSET_RATE, reg & 0xff7f);
+	snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x0200, 0x0000);
+	snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0080, 0x0000);
 	wm9713->pll_in = freq_in;
 
 	/* wait 10ms AC97 link frames for the link to stabilise */
@@ -863,10 +887,10 @@
 	int tristate)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0x9fff;
 
 	if (tristate)
-		ac97_write(codec, AC97_CENTER_LFE_MASTER, reg);
+		snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+				    0x6000, 0x0000);
 
 	return 0;
 }
@@ -879,36 +903,30 @@
 		int div_id, int div)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 reg;
 
 	switch (div_id) {
 	case WM9713_PCMCLK_DIV:
-		reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xf0ff;
-		ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+		snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, div);
 		break;
 	case WM9713_CLKA_MULT:
-		reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xfffd;
-		ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+		snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0002, div);
 		break;
 	case WM9713_CLKB_MULT:
-		reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xfffb;
-		ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+		snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0004, div);
 		break;
 	case WM9713_HIFI_DIV:
-		reg = ac97_read(codec, AC97_HANDSET_RATE) & 0x8fff;
-		ac97_write(codec, AC97_HANDSET_RATE, reg | div);
+		snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x7000, div);
 		break;
 	case WM9713_PCMBCLK_DIV:
-		reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xf1ff;
-		ac97_write(codec, AC97_CENTER_LFE_MASTER, reg | div);
+		snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER, 0x0e00, div);
 		break;
 	case WM9713_PCMCLK_PLL_DIV:
-		reg = ac97_read(codec, AC97_LINE1_LEVEL) & 0xff80;
-		ac97_write(codec, AC97_LINE1_LEVEL, reg | 0x60 | div);
+		snd_soc_update_bits(codec, AC97_LINE1_LEVEL,
+				    0x007f, div | 0x60);
 		break;
 	case WM9713_HIFI_PLL_DIV:
-		reg = ac97_read(codec, AC97_LINE1_LEVEL) & 0xff80;
-		ac97_write(codec, AC97_LINE1_LEVEL, reg | 0x70 | div);
+		snd_soc_update_bits(codec, AC97_LINE1_LEVEL,
+				    0x007f, div | 0x70);
 		break;
 	default:
 		return -EINVAL;
@@ -921,7 +939,7 @@
 		unsigned int fmt)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
-	u16 gpio = ac97_read(codec, AC97_GPIO_CFG) & 0xffc5;
+	u16 gpio = snd_soc_read(codec, AC97_GPIO_CFG) & 0xffc5;
 	u16 reg = 0x8000;
 
 	/* clock masters */
@@ -974,8 +992,8 @@
 		break;
 	}
 
-	ac97_write(codec, AC97_GPIO_CFG, gpio);
-	ac97_write(codec, AC97_CENTER_LFE_MASTER, reg);
+	snd_soc_write(codec, AC97_GPIO_CFG, gpio);
+	snd_soc_write(codec, AC97_CENTER_LFE_MASTER, reg);
 	return 0;
 }
 
@@ -984,24 +1002,24 @@
 				struct snd_soc_dai *dai)
 {
 	struct snd_soc_codec *codec = dai->codec;
-	u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xfff3;
 
+	/* enable PCM interface in master mode */
 	switch (params_width(params)) {
 	case 16:
 		break;
 	case 20:
-		reg |= 0x0004;
+		snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+				    0x000c, 0x0004);
 		break;
 	case 24:
-		reg |= 0x0008;
+		snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+				    0x000c, 0x0008);
 		break;
 	case 32:
-		reg |= 0x000c;
+		snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER,
+				    0x000c, 0x000c);
 		break;
 	}
-
-	/* enable PCM interface in master mode */
-	ac97_write(codec, AC97_CENTER_LFE_MASTER, reg);
 	return 0;
 }
 
@@ -1011,17 +1029,15 @@
 	struct snd_soc_codec *codec = dai->codec;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int reg;
-	u16 vra;
 
-	vra = ac97_read(codec, AC97_EXTENDED_STATUS);
-	ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
+	snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x0001, 0x0001);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		reg = AC97_PCM_FRONT_DAC_RATE;
 	else
 		reg = AC97_PCM_LR_ADC_RATE;
 
-	return ac97_write(codec, reg, runtime->rate);
+	return snd_soc_write(codec, reg, runtime->rate);
 }
 
 static int ac97_aux_prepare(struct snd_pcm_substream *substream,
@@ -1029,17 +1045,14 @@
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	u16 vra, xsle;
 
-	vra = ac97_read(codec, AC97_EXTENDED_STATUS);
-	ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
-	xsle = ac97_read(codec, AC97_PCI_SID);
-	ac97_write(codec, AC97_PCI_SID, xsle | 0x8000);
+	snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x0001, 0x0001);
+	snd_soc_update_bits(codec, AC97_PCI_SID, 0x8000, 0x8000);
 
 	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
 		return -ENODEV;
 
-	return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate);
+	return snd_soc_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate);
 }
 
 #define WM9713_RATES (SNDRV_PCM_RATE_8000  |	\
@@ -1128,27 +1141,23 @@
 static int wm9713_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
-	u16 reg;
-
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 		/* enable thermal shutdown */
-		reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x1bff;
-		ac97_write(codec, AC97_EXTENDED_MID, reg);
+		snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0xe400, 0x0000);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		/* enable master bias and vmid */
-		reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x3bff;
-		ac97_write(codec, AC97_EXTENDED_MID, reg);
-		ac97_write(codec, AC97_POWERDOWN, 0x0000);
+		snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0xc400, 0x0000);
+		snd_soc_write(codec, AC97_POWERDOWN, 0x0000);
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* disable everything including AC link */
-		ac97_write(codec, AC97_EXTENDED_MID, 0xffff);
-		ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
-		ac97_write(codec, AC97_POWERDOWN, 0xffff);
+		snd_soc_write(codec, AC97_EXTENDED_MID, 0xffff);
+		snd_soc_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
+		snd_soc_write(codec, AC97_POWERDOWN, 0xffff);
 		break;
 	}
 	return 0;
@@ -1156,16 +1165,14 @@
 
 static int wm9713_soc_suspend(struct snd_soc_codec *codec)
 {
-	u16 reg;
-
 	/* Disable everything except touchpanel - that will be handled
 	 * by the touch driver and left disabled if touch is not in
 	 * use. */
-	reg = ac97_read(codec, AC97_EXTENDED_MID);
-	ac97_write(codec, AC97_EXTENDED_MID, reg | 0x7fff);
-	ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
-	ac97_write(codec, AC97_POWERDOWN, 0x6f00);
-	ac97_write(codec, AC97_POWERDOWN, 0xffff);
+	snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x7fff,
+				 0x7fff);
+	snd_soc_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
+	snd_soc_write(codec, AC97_POWERDOWN, 0x6f00);
+	snd_soc_write(codec, AC97_POWERDOWN, 0xffff);
 
 	return 0;
 }
@@ -1173,8 +1180,7 @@
 static int wm9713_soc_resume(struct snd_soc_codec *codec)
 {
 	struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
-	int i, ret;
-	u16 *cache = codec->reg_cache;
+	int ret;
 
 	ret = snd_ac97_reset(wm9713->ac97, true, WM9713_VENDOR_ID,
 		WM9713_VENDOR_ID_MASK);
@@ -1189,12 +1195,8 @@
 
 	/* only synchronise the codec if warm reset failed */
 	if (ret == 0) {
-		for (i = 2; i < ARRAY_SIZE(wm9713_reg) << 1; i += 2) {
-			if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID ||
-				i == AC97_EXTENDED_MSTATUS || i > 0x66)
-				continue;
-			soc_ac97_ops->write(wm9713->ac97, i, cache[i>>1]);
-		}
+		regcache_mark_dirty(codec->component.regmap);
+		snd_soc_cache_sync(codec);
 	}
 
 	return ret;
@@ -1203,16 +1205,23 @@
 static int wm9713_soc_probe(struct snd_soc_codec *codec)
 {
 	struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
-	int reg;
+	struct regmap *regmap;
 
 	wm9713->ac97 = snd_soc_new_ac97_codec(codec, WM9713_VENDOR_ID,
 		WM9713_VENDOR_ID_MASK);
 	if (IS_ERR(wm9713->ac97))
 		return PTR_ERR(wm9713->ac97);
 
+	regmap = devm_regmap_init_ac97(wm9713->ac97, &wm9713_regmap_config);
+	if (IS_ERR(regmap)) {
+		snd_soc_free_ac97_codec(wm9713->ac97);
+		return PTR_ERR(regmap);
+	}
+
+	snd_soc_codec_init_regmap(codec, regmap);
+
 	/* unmute the adc - move to kcontrol */
-	reg = ac97_read(codec, AC97_CD) & 0x7fff;
-	ac97_write(codec, AC97_CD, reg);
+	snd_soc_update_bits(codec, AC97_CD, 0x7fff, 0x0000);
 
 	return 0;
 }
@@ -1221,6 +1230,7 @@
 {
 	struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
 
+	snd_soc_codec_exit_regmap(codec);
 	snd_soc_free_ac97_codec(wm9713->ac97);
 	return 0;
 }
@@ -1230,13 +1240,7 @@
 	.remove = 	wm9713_soc_remove,
 	.suspend =	wm9713_soc_suspend,
 	.resume = 	wm9713_soc_resume,
-	.read = ac97_read,
-	.write = ac97_write,
 	.set_bias_level = wm9713_set_bias_level,
-	.reg_cache_size = ARRAY_SIZE(wm9713_reg),
-	.reg_word_size = sizeof(u16),
-	.reg_cache_step = 2,
-	.reg_cache_default = wm9713_reg,
 
 	.controls = wm9713_snd_ac97_controls,
 	.num_controls = ARRAY_SIZE(wm9713_snd_ac97_controls),
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 0bb415a..33806d4 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -201,27 +201,194 @@
 	}
 }
 
-#define WM_ADSP_NUM_FW 4
+#define WM_ADSP_FW_MBC_VSS  0
+#define WM_ADSP_FW_HIFI     1
+#define WM_ADSP_FW_TX       2
+#define WM_ADSP_FW_TX_SPK   3
+#define WM_ADSP_FW_RX       4
+#define WM_ADSP_FW_RX_ANC   5
+#define WM_ADSP_FW_CTRL     6
+#define WM_ADSP_FW_ASR      7
+#define WM_ADSP_FW_TRACE    8
+#define WM_ADSP_FW_SPK_PROT 9
+#define WM_ADSP_FW_MISC     10
 
-#define WM_ADSP_FW_MBC_VSS 0
-#define WM_ADSP_FW_TX      1
-#define WM_ADSP_FW_TX_SPK  2
-#define WM_ADSP_FW_RX_ANC  3
+#define WM_ADSP_NUM_FW      11
 
 static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
-	[WM_ADSP_FW_MBC_VSS] = "MBC/VSS",
-	[WM_ADSP_FW_TX] =      "Tx",
-	[WM_ADSP_FW_TX_SPK] =  "Tx Speaker",
-	[WM_ADSP_FW_RX_ANC] =  "Rx ANC",
+	[WM_ADSP_FW_MBC_VSS] =  "MBC/VSS",
+	[WM_ADSP_FW_HIFI] =     "MasterHiFi",
+	[WM_ADSP_FW_TX] =       "Tx",
+	[WM_ADSP_FW_TX_SPK] =   "Tx Speaker",
+	[WM_ADSP_FW_RX] =       "Rx",
+	[WM_ADSP_FW_RX_ANC] =   "Rx ANC",
+	[WM_ADSP_FW_CTRL] =     "Voice Ctrl",
+	[WM_ADSP_FW_ASR] =      "ASR Assist",
+	[WM_ADSP_FW_TRACE] =    "Dbg Trace",
+	[WM_ADSP_FW_SPK_PROT] = "Protection",
+	[WM_ADSP_FW_MISC] =     "Misc",
 };
 
-static struct {
+struct wm_adsp_system_config_xm_hdr {
+	__be32 sys_enable;
+	__be32 fw_id;
+	__be32 fw_rev;
+	__be32 boot_status;
+	__be32 watchdog;
+	__be32 dma_buffer_size;
+	__be32 rdma[6];
+	__be32 wdma[8];
+	__be32 build_job_name[3];
+	__be32 build_job_number;
+};
+
+struct wm_adsp_alg_xm_struct {
+	__be32 magic;
+	__be32 smoothing;
+	__be32 threshold;
+	__be32 host_buf_ptr;
+	__be32 start_seq;
+	__be32 high_water_mark;
+	__be32 low_water_mark;
+	__be64 smoothed_power;
+};
+
+struct wm_adsp_buffer {
+	__be32 X_buf_base;		/* XM base addr of first X area */
+	__be32 X_buf_size;		/* Size of 1st X area in words */
+	__be32 X_buf_base2;		/* XM base addr of 2nd X area */
+	__be32 X_buf_brk;		/* Total X size in words */
+	__be32 Y_buf_base;		/* YM base addr of Y area */
+	__be32 wrap;			/* Total size X and Y in words */
+	__be32 high_water_mark;		/* Point at which IRQ is asserted */
+	__be32 irq_count;		/* bits 1-31 count IRQ assertions */
+	__be32 irq_ack;			/* acked IRQ count, bit 0 enables IRQ */
+	__be32 next_write_index;	/* word index of next write */
+	__be32 next_read_index;		/* word index of next read */
+	__be32 error;			/* error if any */
+	__be32 oldest_block_index;	/* word index of oldest surviving */
+	__be32 requested_rewind;	/* how many blocks rewind was done */
+	__be32 reserved_space;		/* internal */
+	__be32 min_free;		/* min free space since stream start */
+	__be32 blocks_written[2];	/* total blocks written (64 bit) */
+	__be32 words_written[2];	/* total words written (64 bit) */
+};
+
+struct wm_adsp_compr_buf {
+	struct wm_adsp *dsp;
+
+	struct wm_adsp_buffer_region *regions;
+	u32 host_buf_ptr;
+
+	u32 error;
+	u32 irq_count;
+	int read_index;
+	int avail;
+};
+
+struct wm_adsp_compr {
+	struct wm_adsp *dsp;
+	struct wm_adsp_compr_buf *buf;
+
+	struct snd_compr_stream *stream;
+	struct snd_compressed_buffer size;
+
+	u32 *raw_buf;
+	unsigned int copied_total;
+};
+
+#define WM_ADSP_DATA_WORD_SIZE         3
+
+#define WM_ADSP_MIN_FRAGMENTS          1
+#define WM_ADSP_MAX_FRAGMENTS          256
+#define WM_ADSP_MIN_FRAGMENT_SIZE      (64 * WM_ADSP_DATA_WORD_SIZE)
+#define WM_ADSP_MAX_FRAGMENT_SIZE      (4096 * WM_ADSP_DATA_WORD_SIZE)
+
+#define WM_ADSP_ALG_XM_STRUCT_MAGIC    0x49aec7
+
+#define HOST_BUFFER_FIELD(field) \
+	(offsetof(struct wm_adsp_buffer, field) / sizeof(__be32))
+
+#define ALG_XM_FIELD(field) \
+	(offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32))
+
+static int wm_adsp_buffer_init(struct wm_adsp *dsp);
+static int wm_adsp_buffer_free(struct wm_adsp *dsp);
+
+struct wm_adsp_buffer_region {
+	unsigned int offset;
+	unsigned int cumulative_size;
+	unsigned int mem_type;
+	unsigned int base_addr;
+};
+
+struct wm_adsp_buffer_region_def {
+	unsigned int mem_type;
+	unsigned int base_offset;
+	unsigned int size_offset;
+};
+
+static struct wm_adsp_buffer_region_def ez2control_regions[] = {
+	{
+		.mem_type = WMFW_ADSP2_XM,
+		.base_offset = HOST_BUFFER_FIELD(X_buf_base),
+		.size_offset = HOST_BUFFER_FIELD(X_buf_size),
+	},
+	{
+		.mem_type = WMFW_ADSP2_XM,
+		.base_offset = HOST_BUFFER_FIELD(X_buf_base2),
+		.size_offset = HOST_BUFFER_FIELD(X_buf_brk),
+	},
+	{
+		.mem_type = WMFW_ADSP2_YM,
+		.base_offset = HOST_BUFFER_FIELD(Y_buf_base),
+		.size_offset = HOST_BUFFER_FIELD(wrap),
+	},
+};
+
+struct wm_adsp_fw_caps {
+	u32 id;
+	struct snd_codec_desc desc;
+	int num_regions;
+	struct wm_adsp_buffer_region_def *region_defs;
+};
+
+static const struct wm_adsp_fw_caps ez2control_caps[] = {
+	{
+		.id = SND_AUDIOCODEC_BESPOKE,
+		.desc = {
+			.max_ch = 1,
+			.sample_rates = { 16000 },
+			.num_sample_rates = 1,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.num_regions = ARRAY_SIZE(ez2control_regions),
+		.region_defs = ez2control_regions,
+	},
+};
+
+static const struct {
 	const char *file;
+	int compr_direction;
+	int num_caps;
+	const struct wm_adsp_fw_caps *caps;
 } wm_adsp_fw[WM_ADSP_NUM_FW] = {
-	[WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" },
-	[WM_ADSP_FW_TX] =      { .file = "tx" },
-	[WM_ADSP_FW_TX_SPK] =  { .file = "tx-spk" },
-	[WM_ADSP_FW_RX_ANC] =  { .file = "rx-anc" },
+	[WM_ADSP_FW_MBC_VSS] =  { .file = "mbc-vss" },
+	[WM_ADSP_FW_HIFI] =     { .file = "hifi" },
+	[WM_ADSP_FW_TX] =       { .file = "tx" },
+	[WM_ADSP_FW_TX_SPK] =   { .file = "tx-spk" },
+	[WM_ADSP_FW_RX] =       { .file = "rx" },
+	[WM_ADSP_FW_RX_ANC] =   { .file = "rx-anc" },
+	[WM_ADSP_FW_CTRL] =     {
+		.file = "ctrl",
+		.compr_direction = SND_COMPRESS_CAPTURE,
+		.num_caps = ARRAY_SIZE(ez2control_caps),
+		.caps = ez2control_caps,
+	},
+	[WM_ADSP_FW_ASR] =      { .file = "asr" },
+	[WM_ADSP_FW_TRACE] =    { .file = "trace" },
+	[WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" },
+	[WM_ADSP_FW_MISC] =     { .file = "misc" },
 };
 
 struct wm_coeff_ctl_ops {
@@ -254,30 +421,24 @@
 {
 	char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
 
-	mutex_lock(&dsp->debugfs_lock);
 	kfree(dsp->wmfw_file_name);
 	dsp->wmfw_file_name = tmp;
-	mutex_unlock(&dsp->debugfs_lock);
 }
 
 static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s)
 {
 	char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
 
-	mutex_lock(&dsp->debugfs_lock);
 	kfree(dsp->bin_file_name);
 	dsp->bin_file_name = tmp;
-	mutex_unlock(&dsp->debugfs_lock);
 }
 
 static void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
 {
-	mutex_lock(&dsp->debugfs_lock);
 	kfree(dsp->wmfw_file_name);
 	kfree(dsp->bin_file_name);
 	dsp->wmfw_file_name = NULL;
 	dsp->bin_file_name = NULL;
-	mutex_unlock(&dsp->debugfs_lock);
 }
 
 static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file,
@@ -287,7 +448,7 @@
 	struct wm_adsp *dsp = file->private_data;
 	ssize_t ret;
 
-	mutex_lock(&dsp->debugfs_lock);
+	mutex_lock(&dsp->pwr_lock);
 
 	if (!dsp->wmfw_file_name || !dsp->running)
 		ret = 0;
@@ -296,7 +457,7 @@
 					      dsp->wmfw_file_name,
 					      strlen(dsp->wmfw_file_name));
 
-	mutex_unlock(&dsp->debugfs_lock);
+	mutex_unlock(&dsp->pwr_lock);
 	return ret;
 }
 
@@ -307,7 +468,7 @@
 	struct wm_adsp *dsp = file->private_data;
 	ssize_t ret;
 
-	mutex_lock(&dsp->debugfs_lock);
+	mutex_lock(&dsp->pwr_lock);
 
 	if (!dsp->bin_file_name || !dsp->running)
 		ret = 0;
@@ -316,7 +477,7 @@
 					      dsp->bin_file_name,
 					      strlen(dsp->bin_file_name));
 
-	mutex_unlock(&dsp->debugfs_lock);
+	mutex_unlock(&dsp->pwr_lock);
 	return ret;
 }
 
@@ -436,6 +597,7 @@
 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
 
 	if (ucontrol->value.integer.value[0] == dsp[e->shift_l].fw)
 		return 0;
@@ -443,12 +605,16 @@
 	if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
 		return -EINVAL;
 
-	if (dsp[e->shift_l].running)
-		return -EBUSY;
+	mutex_lock(&dsp[e->shift_l].pwr_lock);
 
-	dsp[e->shift_l].fw = ucontrol->value.integer.value[0];
+	if (dsp[e->shift_l].running || dsp[e->shift_l].compr)
+		ret = -EBUSY;
+	else
+		dsp[e->shift_l].fw = ucontrol->value.integer.value[0];
 
-	return 0;
+	mutex_unlock(&dsp[e->shift_l].pwr_lock);
+
+	return ret;
 }
 
 static const struct soc_enum wm_adsp_fw_enum[] = {
@@ -523,10 +689,10 @@
 		 be16_to_cpu(scratch[3]));
 }
 
-static int wm_coeff_info(struct snd_kcontrol *kcontrol,
+static int wm_coeff_info(struct snd_kcontrol *kctl,
 			 struct snd_ctl_elem_info *uinfo)
 {
-	struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
+	struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value;
 
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
 	uinfo->count = ctl->len;
@@ -572,19 +738,24 @@
 	return 0;
 }
 
-static int wm_coeff_put(struct snd_kcontrol *kcontrol,
+static int wm_coeff_put(struct snd_kcontrol *kctl,
 			struct snd_ctl_elem_value *ucontrol)
 {
-	struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
+	struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value;
 	char *p = ucontrol->value.bytes.data;
+	int ret = 0;
+
+	mutex_lock(&ctl->dsp->pwr_lock);
 
 	memcpy(ctl->cache, p, ctl->len);
 
 	ctl->set = 1;
-	if (!ctl->enabled)
-		return 0;
+	if (ctl->enabled)
+		ret = wm_coeff_write_control(ctl, p, ctl->len);
 
-	return wm_coeff_write_control(ctl, p, ctl->len);
+	mutex_unlock(&ctl->dsp->pwr_lock);
+
+	return ret;
 }
 
 static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
@@ -626,22 +797,30 @@
 	return 0;
 }
 
-static int wm_coeff_get(struct snd_kcontrol *kcontrol,
+static int wm_coeff_get(struct snd_kcontrol *kctl,
 			struct snd_ctl_elem_value *ucontrol)
 {
-	struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
+	struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value;
 	char *p = ucontrol->value.bytes.data;
+	int ret = 0;
+
+	mutex_lock(&ctl->dsp->pwr_lock);
 
 	if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
 		if (ctl->enabled)
-			return wm_coeff_read_control(ctl, p, ctl->len);
+			ret = wm_coeff_read_control(ctl, p, ctl->len);
 		else
-			return -EPERM;
+			ret = -EPERM;
+	} else {
+		if (!ctl->flags && ctl->enabled)
+			ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len);
+
+		memcpy(p, ctl->cache, ctl->len);
 	}
 
-	memcpy(p, ctl->cache, ctl->len);
+	mutex_unlock(&ctl->dsp->pwr_lock);
 
-	return 0;
+	return ret;
 }
 
 struct wmfw_ctl_work {
@@ -808,8 +987,7 @@
 		break;
 	}
 
-	list_for_each_entry(ctl, &dsp->ctl_list,
-			    list) {
+	list_for_each_entry(ctl, &dsp->ctl_list, list) {
 		if (!strcmp(ctl->name, name)) {
 			if (!ctl->enabled)
 				ctl->enabled = 1;
@@ -1088,7 +1266,7 @@
 		goto out_fw;
 	}
 
-	header = (void*)&firmware->data[0];
+	header = (void *)&firmware->data[0];
 
 	if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
 		adsp_err(dsp, "%s: invalid magic\n", file);
@@ -1168,7 +1346,7 @@
 		offset = le32_to_cpu(region->offset) & 0xffffff;
 		type = be32_to_cpu(region->type) & 0xff;
 		mem = wm_adsp_find_region(dsp, type);
-		
+
 		switch (type) {
 		case WMFW_NAME_TEXT:
 			region_name = "Firmware name";
@@ -1333,6 +1511,19 @@
 	return alg;
 }
 
+static struct wm_adsp_alg_region *
+	wm_adsp_find_alg_region(struct wm_adsp *dsp, int type, unsigned int id)
+{
+	struct wm_adsp_alg_region *alg_region;
+
+	list_for_each_entry(alg_region, &dsp->alg_regions, list) {
+		if (id == alg_region->alg && type == alg_region->type)
+			return alg_region;
+	}
+
+	return NULL;
+}
+
 static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp,
 							int type, __be32 id,
 							__be32 base)
@@ -1625,7 +1816,7 @@
 		goto out_fw;
 	}
 
-	hdr = (void*)&firmware->data[0];
+	hdr = (void *)&firmware->data[0];
 	if (memcmp(hdr->magic, "WMDR", 4) != 0) {
 		adsp_err(dsp, "%s: invalid magic\n", file);
 		goto out_fw;
@@ -1651,7 +1842,7 @@
 	blocks = 0;
 	while (pos < firmware->size &&
 	       pos - firmware->size > sizeof(*blk)) {
-		blk = (void*)(&firmware->data[pos]);
+		blk = (void *)(&firmware->data[pos]);
 
 		type = le16_to_cpu(blk->type);
 		offset = le16_to_cpu(blk->offset);
@@ -1705,22 +1896,16 @@
 				break;
 			}
 
-			reg = 0;
-			list_for_each_entry(alg_region,
-					    &dsp->alg_regions, list) {
-				if (le32_to_cpu(blk->id) == alg_region->alg &&
-				    type == alg_region->type) {
-					reg = alg_region->base;
-					reg = wm_adsp_region_to_reg(mem,
-								    reg);
-					reg += offset;
-					break;
-				}
-			}
-
-			if (reg == 0)
+			alg_region = wm_adsp_find_alg_region(dsp, type,
+						le32_to_cpu(blk->id));
+			if (alg_region) {
+				reg = alg_region->base;
+				reg = wm_adsp_region_to_reg(mem, reg);
+				reg += offset;
+			} else {
 				adsp_err(dsp, "No %x for algorithm %x\n",
 					 type, le32_to_cpu(blk->id));
+			}
 			break;
 
 		default:
@@ -1778,9 +1963,8 @@
 {
 	INIT_LIST_HEAD(&dsp->alg_regions);
 
-#ifdef CONFIG_DEBUG_FS
-	mutex_init(&dsp->debugfs_lock);
-#endif
+	mutex_init(&dsp->pwr_lock);
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(wm_adsp1_init);
@@ -1795,10 +1979,12 @@
 	struct wm_adsp_alg_region *alg_region;
 	struct wm_coeff_ctl *ctl;
 	int ret;
-	int val;
+	unsigned int val;
 
 	dsp->card = codec->component.card;
 
+	mutex_lock(&dsp->pwr_lock);
+
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
@@ -1808,12 +1994,12 @@
 		 * For simplicity set the DSP clock rate to be the
 		 * SYSCLK rate rather than making it configurable.
 		 */
-		if(dsp->sysclk_reg) {
+		if (dsp->sysclk_reg) {
 			ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
 			if (ret != 0) {
 				adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
 				ret);
-				return ret;
+				goto err_mutex;
 			}
 
 			val = (val & dsp->sysclk_mask)
@@ -1825,31 +2011,31 @@
 			if (ret != 0) {
 				adsp_err(dsp, "Failed to set clock rate: %d\n",
 					 ret);
-				return ret;
+				goto err_mutex;
 			}
 		}
 
 		ret = wm_adsp_load(dsp);
 		if (ret != 0)
-			goto err;
+			goto err_ena;
 
 		ret = wm_adsp1_setup_algs(dsp);
 		if (ret != 0)
-			goto err;
+			goto err_ena;
 
 		ret = wm_adsp_load_coeff(dsp);
 		if (ret != 0)
-			goto err;
+			goto err_ena;
 
 		/* Initialize caches for enabled and unset controls */
 		ret = wm_coeff_init_control_caches(dsp);
 		if (ret != 0)
-			goto err;
+			goto err_ena;
 
 		/* Sync set controls */
 		ret = wm_coeff_sync_controls(dsp);
 		if (ret != 0)
-			goto err;
+			goto err_ena;
 
 		/* Start the core running */
 		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
@@ -1884,11 +2070,16 @@
 		break;
 	}
 
+	mutex_unlock(&dsp->pwr_lock);
+
 	return 0;
 
-err:
+err_ena:
 	regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
 			   ADSP1_SYS_ENA, 0);
+err_mutex:
+	mutex_unlock(&dsp->pwr_lock);
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(wm_adsp1_event);
@@ -1934,6 +2125,8 @@
 	int ret;
 	unsigned int val;
 
+	mutex_lock(&dsp->pwr_lock);
+
 	/*
 	 * For simplicity set the DSP clock rate to be the
 	 * SYSCLK rate rather than making it configurable.
@@ -1941,7 +2134,7 @@
 	ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
 	if (ret != 0) {
 		adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret);
-		return;
+		goto err_mutex;
 	}
 	val = (val & ARIZONA_SYSCLK_FREQ_MASK)
 		>> ARIZONA_SYSCLK_FREQ_SHIFT;
@@ -1951,42 +2144,46 @@
 				       ADSP2_CLK_SEL_MASK, val);
 	if (ret != 0) {
 		adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
-		return;
+		goto err_mutex;
 	}
 
 	ret = wm_adsp2_ena(dsp);
 	if (ret != 0)
-		return;
+		goto err_mutex;
 
 	ret = wm_adsp_load(dsp);
 	if (ret != 0)
-		goto err;
+		goto err_ena;
 
 	ret = wm_adsp2_setup_algs(dsp);
 	if (ret != 0)
-		goto err;
+		goto err_ena;
 
 	ret = wm_adsp_load_coeff(dsp);
 	if (ret != 0)
-		goto err;
+		goto err_ena;
 
 	/* Initialize caches for enabled and unset controls */
 	ret = wm_coeff_init_control_caches(dsp);
 	if (ret != 0)
-		goto err;
+		goto err_ena;
 
 	/* Sync set controls */
 	ret = wm_coeff_sync_controls(dsp);
 	if (ret != 0)
-		goto err;
+		goto err_ena;
 
 	dsp->running = true;
 
+	mutex_unlock(&dsp->pwr_lock);
+
 	return;
 
-err:
+err_ena:
 	regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
 			   ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
+err_mutex:
+	mutex_unlock(&dsp->pwr_lock);
 }
 
 int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
@@ -2033,12 +2230,18 @@
 					 ADSP2_CORE_ENA | ADSP2_START);
 		if (ret != 0)
 			goto err;
+
+		if (wm_adsp_fw[dsp->fw].num_caps != 0)
+			ret = wm_adsp_buffer_init(dsp);
+
 		break;
 
 	case SND_SOC_DAPM_PRE_PMD:
 		/* Log firmware state, it can be useful for analysis */
 		wm_adsp2_show_fw_status(dsp);
 
+		mutex_lock(&dsp->pwr_lock);
+
 		wm_adsp_debugfs_clear(dsp);
 
 		dsp->fw_id = 0;
@@ -2065,6 +2268,11 @@
 			kfree(alg_region);
 		}
 
+		if (wm_adsp_fw[dsp->fw].num_caps != 0)
+			wm_adsp_buffer_free(dsp);
+
+		mutex_unlock(&dsp->pwr_lock);
+
 		adsp_dbg(dsp, "Shutdown complete\n");
 		break;
 
@@ -2117,11 +2325,724 @@
 	INIT_LIST_HEAD(&dsp->ctl_list);
 	INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
 
-#ifdef CONFIG_DEBUG_FS
-	mutex_init(&dsp->debugfs_lock);
-#endif
+	mutex_init(&dsp->pwr_lock);
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_init);
 
+int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
+{
+	struct wm_adsp_compr *compr;
+	int ret = 0;
+
+	mutex_lock(&dsp->pwr_lock);
+
+	if (wm_adsp_fw[dsp->fw].num_caps == 0) {
+		adsp_err(dsp, "Firmware does not support compressed API\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
+		adsp_err(dsp, "Firmware does not support stream direction\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (dsp->compr) {
+		/* It is expect this limitation will be removed in future */
+		adsp_err(dsp, "Only a single stream supported per DSP\n");
+		ret = -EBUSY;
+		goto out;
+	}
+
+	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
+	if (!compr) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	compr->dsp = dsp;
+	compr->stream = stream;
+
+	dsp->compr = compr;
+
+	stream->runtime->private_data = compr;
+
+out:
+	mutex_unlock(&dsp->pwr_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_open);
+
+int wm_adsp_compr_free(struct snd_compr_stream *stream)
+{
+	struct wm_adsp_compr *compr = stream->runtime->private_data;
+	struct wm_adsp *dsp = compr->dsp;
+
+	mutex_lock(&dsp->pwr_lock);
+
+	dsp->compr = NULL;
+
+	kfree(compr->raw_buf);
+	kfree(compr);
+
+	mutex_unlock(&dsp->pwr_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_free);
+
+static int wm_adsp_compr_check_params(struct snd_compr_stream *stream,
+				      struct snd_compr_params *params)
+{
+	struct wm_adsp_compr *compr = stream->runtime->private_data;
+	struct wm_adsp *dsp = compr->dsp;
+	const struct wm_adsp_fw_caps *caps;
+	const struct snd_codec_desc *desc;
+	int i, j;
+
+	if (params->buffer.fragment_size < WM_ADSP_MIN_FRAGMENT_SIZE ||
+	    params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE ||
+	    params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS ||
+	    params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS ||
+	    params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) {
+		adsp_err(dsp, "Invalid buffer fragsize=%d fragments=%d\n",
+			 params->buffer.fragment_size,
+			 params->buffer.fragments);
+
+		return -EINVAL;
+	}
+
+	for (i = 0; i < wm_adsp_fw[dsp->fw].num_caps; i++) {
+		caps = &wm_adsp_fw[dsp->fw].caps[i];
+		desc = &caps->desc;
+
+		if (caps->id != params->codec.id)
+			continue;
+
+		if (stream->direction == SND_COMPRESS_PLAYBACK) {
+			if (desc->max_ch < params->codec.ch_out)
+				continue;
+		} else {
+			if (desc->max_ch < params->codec.ch_in)
+				continue;
+		}
+
+		if (!(desc->formats & (1 << params->codec.format)))
+			continue;
+
+		for (j = 0; j < desc->num_sample_rates; ++j)
+			if (desc->sample_rates[j] == params->codec.sample_rate)
+				return 0;
+	}
+
+	adsp_err(dsp, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n",
+		 params->codec.id, params->codec.ch_in, params->codec.ch_out,
+		 params->codec.sample_rate, params->codec.format);
+	return -EINVAL;
+}
+
+static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr)
+{
+	return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE;
+}
+
+int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
+			     struct snd_compr_params *params)
+{
+	struct wm_adsp_compr *compr = stream->runtime->private_data;
+	unsigned int size;
+	int ret;
+
+	ret = wm_adsp_compr_check_params(stream, params);
+	if (ret)
+		return ret;
+
+	compr->size = params->buffer;
+
+	adsp_dbg(compr->dsp, "fragment_size=%d fragments=%d\n",
+		 compr->size.fragment_size, compr->size.fragments);
+
+	size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf);
+	compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL);
+	if (!compr->raw_buf)
+		return -ENOMEM;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
+
+int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
+			   struct snd_compr_caps *caps)
+{
+	struct wm_adsp_compr *compr = stream->runtime->private_data;
+	int fw = compr->dsp->fw;
+	int i;
+
+	if (wm_adsp_fw[fw].caps) {
+		for (i = 0; i < wm_adsp_fw[fw].num_caps; i++)
+			caps->codecs[i] = wm_adsp_fw[fw].caps[i].id;
+
+		caps->num_codecs = i;
+		caps->direction = wm_adsp_fw[fw].compr_direction;
+
+		caps->min_fragment_size = WM_ADSP_MIN_FRAGMENT_SIZE;
+		caps->max_fragment_size = WM_ADSP_MAX_FRAGMENT_SIZE;
+		caps->min_fragments = WM_ADSP_MIN_FRAGMENTS;
+		caps->max_fragments = WM_ADSP_MAX_FRAGMENTS;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps);
+
+static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type,
+				   unsigned int mem_addr,
+				   unsigned int num_words, u32 *data)
+{
+	struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
+	unsigned int i, reg;
+	int ret;
+
+	if (!mem)
+		return -EINVAL;
+
+	reg = wm_adsp_region_to_reg(mem, mem_addr);
+
+	ret = regmap_raw_read(dsp->regmap, reg, data,
+			      sizeof(*data) * num_words);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < num_words; ++i)
+		data[i] = be32_to_cpu(data[i]) & 0x00ffffffu;
+
+	return 0;
+}
+
+static inline int wm_adsp_read_data_word(struct wm_adsp *dsp, int mem_type,
+					 unsigned int mem_addr, u32 *data)
+{
+	return wm_adsp_read_data_block(dsp, mem_type, mem_addr, 1, data);
+}
+
+static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type,
+				   unsigned int mem_addr, u32 data)
+{
+	struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type);
+	unsigned int reg;
+
+	if (!mem)
+		return -EINVAL;
+
+	reg = wm_adsp_region_to_reg(mem, mem_addr);
+
+	data = cpu_to_be32(data & 0x00ffffffu);
+
+	return regmap_raw_write(dsp->regmap, reg, &data, sizeof(data));
+}
+
+static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
+				      unsigned int field_offset, u32 *data)
+{
+	return wm_adsp_read_data_word(buf->dsp, WMFW_ADSP2_XM,
+				      buf->host_buf_ptr + field_offset, data);
+}
+
+static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
+				       unsigned int field_offset, u32 data)
+{
+	return wm_adsp_write_data_word(buf->dsp, WMFW_ADSP2_XM,
+				       buf->host_buf_ptr + field_offset, data);
+}
+
+static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
+{
+	struct wm_adsp_alg_region *alg_region;
+	struct wm_adsp *dsp = buf->dsp;
+	u32 xmalg, addr, magic;
+	int i, ret;
+
+	alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
+	xmalg = sizeof(struct wm_adsp_system_config_xm_hdr) / sizeof(__be32);
+
+	addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
+	ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic);
+	if (ret < 0)
+		return ret;
+
+	if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC)
+		return -EINVAL;
+
+	addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr);
+	for (i = 0; i < 5; ++i) {
+		ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr,
+					     &buf->host_buf_ptr);
+		if (ret < 0)
+			return ret;
+
+		if (buf->host_buf_ptr)
+			break;
+
+		usleep_range(1000, 2000);
+	}
+
+	if (!buf->host_buf_ptr)
+		return -EIO;
+
+	adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr);
+
+	return 0;
+}
+
+static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
+{
+	const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
+	struct wm_adsp_buffer_region *region;
+	u32 offset = 0;
+	int i, ret;
+
+	for (i = 0; i < caps->num_regions; ++i) {
+		region = &buf->regions[i];
+
+		region->offset = offset;
+		region->mem_type = caps->region_defs[i].mem_type;
+
+		ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset,
+					  &region->base_addr);
+		if (ret < 0)
+			return ret;
+
+		ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset,
+					  &offset);
+		if (ret < 0)
+			return ret;
+
+		region->cumulative_size = offset;
+
+		adsp_dbg(buf->dsp,
+			 "region=%d type=%d base=%04x off=%04x size=%04x\n",
+			 i, region->mem_type, region->base_addr,
+			 region->offset, region->cumulative_size);
+	}
+
+	return 0;
+}
+
+static int wm_adsp_buffer_init(struct wm_adsp *dsp)
+{
+	struct wm_adsp_compr_buf *buf;
+	int ret;
+
+	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	buf->dsp = dsp;
+	buf->read_index = -1;
+	buf->irq_count = 0xFFFFFFFF;
+
+	ret = wm_adsp_buffer_locate(buf);
+	if (ret < 0) {
+		adsp_err(dsp, "Failed to acquire host buffer: %d\n", ret);
+		goto err_buffer;
+	}
+
+	buf->regions = kcalloc(wm_adsp_fw[dsp->fw].caps->num_regions,
+			       sizeof(*buf->regions), GFP_KERNEL);
+	if (!buf->regions) {
+		ret = -ENOMEM;
+		goto err_buffer;
+	}
+
+	ret = wm_adsp_buffer_populate(buf);
+	if (ret < 0) {
+		adsp_err(dsp, "Failed to populate host buffer: %d\n", ret);
+		goto err_regions;
+	}
+
+	dsp->buffer = buf;
+
+	return 0;
+
+err_regions:
+	kfree(buf->regions);
+err_buffer:
+	kfree(buf);
+	return ret;
+}
+
+static int wm_adsp_buffer_free(struct wm_adsp *dsp)
+{
+	if (dsp->buffer) {
+		kfree(dsp->buffer->regions);
+		kfree(dsp->buffer);
+
+		dsp->buffer = NULL;
+	}
+
+	return 0;
+}
+
+static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr)
+{
+	return compr->buf != NULL;
+}
+
+static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)
+{
+	/*
+	 * Note this will be more complex once each DSP can support multiple
+	 * streams
+	 */
+	if (!compr->dsp->buffer)
+		return -EINVAL;
+
+	compr->buf = compr->dsp->buffer;
+
+	return 0;
+}
+
+int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd)
+{
+	struct wm_adsp_compr *compr = stream->runtime->private_data;
+	struct wm_adsp *dsp = compr->dsp;
+	int ret = 0;
+
+	adsp_dbg(dsp, "Trigger: %d\n", cmd);
+
+	mutex_lock(&dsp->pwr_lock);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		if (wm_adsp_compr_attached(compr))
+			break;
+
+		ret = wm_adsp_compr_attach(compr);
+		if (ret < 0) {
+			adsp_err(dsp, "Failed to link buffer and stream: %d\n",
+				 ret);
+			break;
+		}
+
+		/* Trigger the IRQ at one fragment of data */
+		ret = wm_adsp_buffer_write(compr->buf,
+					   HOST_BUFFER_FIELD(high_water_mark),
+					   wm_adsp_compr_frag_words(compr));
+		if (ret < 0) {
+			adsp_err(dsp, "Failed to set high water mark: %d\n",
+				 ret);
+			break;
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&dsp->pwr_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger);
+
+static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf)
+{
+	int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1;
+
+	return buf->regions[last_region].cumulative_size;
+}
+
+static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf)
+{
+	u32 next_read_index, next_write_index;
+	int write_index, read_index, avail;
+	int ret;
+
+	/* Only sync read index if we haven't already read a valid index */
+	if (buf->read_index < 0) {
+		ret = wm_adsp_buffer_read(buf,
+				HOST_BUFFER_FIELD(next_read_index),
+				&next_read_index);
+		if (ret < 0)
+			return ret;
+
+		read_index = sign_extend32(next_read_index, 23);
+
+		if (read_index < 0) {
+			adsp_dbg(buf->dsp, "Avail check on unstarted stream\n");
+			return 0;
+		}
+
+		buf->read_index = read_index;
+	}
+
+	ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index),
+			&next_write_index);
+	if (ret < 0)
+		return ret;
+
+	write_index = sign_extend32(next_write_index, 23);
+
+	avail = write_index - buf->read_index;
+	if (avail < 0)
+		avail += wm_adsp_buffer_size(buf);
+
+	adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
+		 buf->read_index, write_index, avail);
+
+	buf->avail = avail;
+
+	return 0;
+}
+
+int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
+{
+	struct wm_adsp_compr_buf *buf = dsp->buffer;
+	struct wm_adsp_compr *compr = dsp->compr;
+	int ret = 0;
+
+	mutex_lock(&dsp->pwr_lock);
+
+	if (!buf) {
+		adsp_err(dsp, "Spurious buffer IRQ\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	adsp_dbg(dsp, "Handling buffer IRQ\n");
+
+	ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);
+	if (ret < 0) {
+		adsp_err(dsp, "Failed to check buffer error: %d\n", ret);
+		goto out;
+	}
+	if (buf->error != 0) {
+		adsp_err(dsp, "Buffer error occurred: %d\n", buf->error);
+		ret = -EIO;
+		goto out;
+	}
+
+	ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
+				  &buf->irq_count);
+	if (ret < 0) {
+		adsp_err(dsp, "Failed to get irq_count: %d\n", ret);
+		goto out;
+	}
+
+	ret = wm_adsp_buffer_update_avail(buf);
+	if (ret < 0) {
+		adsp_err(dsp, "Error reading avail: %d\n", ret);
+		goto out;
+	}
+
+	if (compr->stream)
+		snd_compr_fragment_elapsed(compr->stream);
+
+out:
+	mutex_unlock(&dsp->pwr_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq);
+
+static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf)
+{
+	if (buf->irq_count & 0x01)
+		return 0;
+
+	adsp_dbg(buf->dsp, "Enable IRQ(0x%x) for next fragment\n",
+		 buf->irq_count);
+
+	buf->irq_count |= 0x01;
+
+	return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack),
+				    buf->irq_count);
+}
+
+int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
+			  struct snd_compr_tstamp *tstamp)
+{
+	struct wm_adsp_compr *compr = stream->runtime->private_data;
+	struct wm_adsp_compr_buf *buf = compr->buf;
+	struct wm_adsp *dsp = compr->dsp;
+	int ret = 0;
+
+	adsp_dbg(dsp, "Pointer request\n");
+
+	mutex_lock(&dsp->pwr_lock);
+
+	if (!compr->buf) {
+		ret = -ENXIO;
+		goto out;
+	}
+
+	if (compr->buf->error) {
+		ret = -EIO;
+		goto out;
+	}
+
+	if (buf->avail < wm_adsp_compr_frag_words(compr)) {
+		ret = wm_adsp_buffer_update_avail(buf);
+		if (ret < 0) {
+			adsp_err(dsp, "Error reading avail: %d\n", ret);
+			goto out;
+		}
+
+		/*
+		 * If we really have less than 1 fragment available tell the
+		 * DSP to inform us once a whole fragment is available.
+		 */
+		if (buf->avail < wm_adsp_compr_frag_words(compr)) {
+			ret = wm_adsp_buffer_reenable_irq(buf);
+			if (ret < 0) {
+				adsp_err(dsp,
+					 "Failed to re-enable buffer IRQ: %d\n",
+					 ret);
+				goto out;
+			}
+		}
+	}
+
+	tstamp->copied_total = compr->copied_total;
+	tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE;
+
+out:
+	mutex_unlock(&dsp->pwr_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer);
+
+static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
+{
+	struct wm_adsp_compr_buf *buf = compr->buf;
+	u8 *pack_in = (u8 *)compr->raw_buf;
+	u8 *pack_out = (u8 *)compr->raw_buf;
+	unsigned int adsp_addr;
+	int mem_type, nwords, max_read;
+	int i, j, ret;
+
+	/* Calculate read parameters */
+	for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i)
+		if (buf->read_index < buf->regions[i].cumulative_size)
+			break;
+
+	if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions)
+		return -EINVAL;
+
+	mem_type = buf->regions[i].mem_type;
+	adsp_addr = buf->regions[i].base_addr +
+		    (buf->read_index - buf->regions[i].offset);
+
+	max_read = wm_adsp_compr_frag_words(compr);
+	nwords = buf->regions[i].cumulative_size - buf->read_index;
+
+	if (nwords > target)
+		nwords = target;
+	if (nwords > buf->avail)
+		nwords = buf->avail;
+	if (nwords > max_read)
+		nwords = max_read;
+	if (!nwords)
+		return 0;
+
+	/* Read data from DSP */
+	ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr,
+				      nwords, compr->raw_buf);
+	if (ret < 0)
+		return ret;
+
+	/* Remove the padding bytes from the data read from the DSP */
+	for (i = 0; i < nwords; i++) {
+		for (j = 0; j < WM_ADSP_DATA_WORD_SIZE; j++)
+			*pack_out++ = *pack_in++;
+
+		pack_in += sizeof(*(compr->raw_buf)) - WM_ADSP_DATA_WORD_SIZE;
+	}
+
+	/* update read index to account for words read */
+	buf->read_index += nwords;
+	if (buf->read_index == wm_adsp_buffer_size(buf))
+		buf->read_index = 0;
+
+	ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index),
+				   buf->read_index);
+	if (ret < 0)
+		return ret;
+
+	/* update avail to account for words read */
+	buf->avail -= nwords;
+
+	return nwords;
+}
+
+static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
+			      char __user *buf, size_t count)
+{
+	struct wm_adsp *dsp = compr->dsp;
+	int ntotal = 0;
+	int nwords, nbytes;
+
+	adsp_dbg(dsp, "Requested read of %zu bytes\n", count);
+
+	if (!compr->buf)
+		return -ENXIO;
+
+	if (compr->buf->error)
+		return -EIO;
+
+	count /= WM_ADSP_DATA_WORD_SIZE;
+
+	do {
+		nwords = wm_adsp_buffer_capture_block(compr, count);
+		if (nwords < 0) {
+			adsp_err(dsp, "Failed to capture block: %d\n", nwords);
+			return nwords;
+		}
+
+		nbytes = nwords * WM_ADSP_DATA_WORD_SIZE;
+
+		adsp_dbg(dsp, "Read %d bytes\n", nbytes);
+
+		if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) {
+			adsp_err(dsp, "Failed to copy data to user: %d, %d\n",
+				 ntotal, nbytes);
+			return -EFAULT;
+		}
+
+		count -= nwords;
+		ntotal += nbytes;
+	} while (nwords > 0 && count > 0);
+
+	compr->copied_total += ntotal;
+
+	return ntotal;
+}
+
+int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf,
+		       size_t count)
+{
+	struct wm_adsp_compr *compr = stream->runtime->private_data;
+	struct wm_adsp *dsp = compr->dsp;
+	int ret;
+
+	mutex_lock(&dsp->pwr_lock);
+
+	if (stream->direction == SND_COMPRESS_CAPTURE)
+		ret = wm_adsp_compr_read(compr, buf, count);
+	else
+		ret = -ENOTSUPP;
+
+	mutex_unlock(&dsp->pwr_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
+
 MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 2d117cf..1a928ec 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -15,6 +15,7 @@
 
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include <sound/compress_driver.h>
 
 #include "wmfw.h"
 
@@ -30,6 +31,9 @@
 	unsigned int base;
 };
 
+struct wm_adsp_compr;
+struct wm_adsp_compr_buf;
+
 struct wm_adsp {
 	const char *part;
 	int num;
@@ -45,8 +49,8 @@
 
 	struct list_head alg_regions;
 
-	int fw_id;
-	int fw_id_version;
+	unsigned int fw_id;
+	unsigned int fw_id_version;
 
 	const struct wm_adsp_region *mem;
 	int num_mems;
@@ -59,9 +63,13 @@
 
 	struct work_struct boot_work;
 
+	struct wm_adsp_compr *compr;
+	struct wm_adsp_compr_buf *buffer;
+
+	struct mutex pwr_lock;
+
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_root;
-	struct mutex debugfs_lock;
 	char *wmfw_file_name;
 	char *bin_file_name;
 #endif
@@ -96,4 +104,18 @@
 int wm_adsp2_event(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol, int event);
 
+extern int wm_adsp_compr_open(struct wm_adsp *dsp,
+			      struct snd_compr_stream *stream);
+extern int wm_adsp_compr_free(struct snd_compr_stream *stream);
+extern int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
+				    struct snd_compr_params *params);
+extern int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
+				  struct snd_compr_caps *caps);
+extern int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd);
+extern int wm_adsp_compr_handle_irq(struct wm_adsp *dsp);
+extern int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
+				 struct snd_compr_tstamp *tstamp);
+extern int wm_adsp_compr_copy(struct snd_compr_stream *stream,
+			      char __user *buf, size_t count);
+
 #endif
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c
index 6e6a70c..ce664c2 100644
--- a/sound/soc/dwc/designware_i2s.c
+++ b/sound/soc/dwc/designware_i2s.c
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 #include <sound/designware_i2s.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -93,7 +94,12 @@
 	struct clk *clk;
 	int active;
 	unsigned int capability;
+	unsigned int quirks;
+	unsigned int i2s_reg_comp1;
+	unsigned int i2s_reg_comp2;
 	struct device *dev;
+	u32 ccr;
+	u32 xfer_resolution;
 
 	/* data related to DMA transfers b/w i2s and DMAC */
 	union dw_i2s_snd_dma_data play_dma_data;
@@ -213,31 +219,58 @@
 	return 0;
 }
 
+static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
+{
+	u32 ch_reg, irq;
+	struct i2s_clk_config_data *config = &dev->config;
+
+
+	i2s_disable_channels(dev, stream);
+
+	for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) {
+		if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			i2s_write_reg(dev->i2s_base, TCR(ch_reg),
+				      dev->xfer_resolution);
+			i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
+			irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
+			i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
+			i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
+		} else {
+			i2s_write_reg(dev->i2s_base, RCR(ch_reg),
+				      dev->xfer_resolution);
+			i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
+			irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
+			i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
+			i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
+		}
+
+	}
+}
+
 static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
 	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
 	struct i2s_clk_config_data *config = &dev->config;
-	u32 ccr, xfer_resolution, ch_reg, irq;
 	int ret;
 
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
 		config->data_width = 16;
-		ccr = 0x00;
-		xfer_resolution = 0x02;
+		dev->ccr = 0x00;
+		dev->xfer_resolution = 0x02;
 		break;
 
 	case SNDRV_PCM_FORMAT_S24_LE:
 		config->data_width = 24;
-		ccr = 0x08;
-		xfer_resolution = 0x04;
+		dev->ccr = 0x08;
+		dev->xfer_resolution = 0x04;
 		break;
 
 	case SNDRV_PCM_FORMAT_S32_LE:
 		config->data_width = 32;
-		ccr = 0x10;
-		xfer_resolution = 0x05;
+		dev->ccr = 0x10;
+		dev->xfer_resolution = 0x05;
 		break;
 
 	default:
@@ -258,27 +291,9 @@
 		return -EINVAL;
 	}
 
-	i2s_disable_channels(dev, substream->stream);
+	dw_i2s_config(dev, substream->stream);
 
-	for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) {
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			i2s_write_reg(dev->i2s_base, TCR(ch_reg),
-				      xfer_resolution);
-			i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
-			irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
-			i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
-			i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
-		} else {
-			i2s_write_reg(dev->i2s_base, RCR(ch_reg),
-				      xfer_resolution);
-			i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
-			irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
-			i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
-			i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
-		}
-	}
-
-	i2s_write_reg(dev->i2s_base, CCR, ccr);
+	i2s_write_reg(dev->i2s_base, CCR, dev->ccr);
 
 	config->sample_rate = params_rate(params);
 
@@ -394,6 +409,23 @@
 };
 
 #ifdef CONFIG_PM
+static int dw_i2s_runtime_suspend(struct device *dev)
+{
+	struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev);
+
+	if (dw_dev->capability & DW_I2S_MASTER)
+		clk_disable(dw_dev->clk);
+	return 0;
+}
+
+static int dw_i2s_runtime_resume(struct device *dev)
+{
+	struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev);
+
+	if (dw_dev->capability & DW_I2S_MASTER)
+		clk_enable(dw_dev->clk);
+	return 0;
+}
 
 static int dw_i2s_suspend(struct snd_soc_dai *dai)
 {
@@ -410,6 +442,11 @@
 
 	if (dev->capability & DW_I2S_MASTER)
 		clk_enable(dev->clk);
+
+	if (dai->playback_active)
+		dw_i2s_config(dev, SNDRV_PCM_STREAM_PLAYBACK);
+	if (dai->capture_active)
+		dw_i2s_config(dev, SNDRV_PCM_STREAM_CAPTURE);
 	return 0;
 }
 
@@ -459,10 +496,14 @@
 	 * Read component parameter registers to extract
 	 * the I2S block's configuration.
 	 */
-	u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
-	u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2);
+	u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1);
+	u32 comp2 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp2);
 	u32 idx;
 
+	if (dev->capability & DWC_I2S_RECORD &&
+			dev->quirks & DW_I2S_QUIRK_COMP_PARAM1)
+		comp1 = comp1 & ~BIT(5);
+
 	if (COMP1_TX_ENABLED(comp1)) {
 		dev_dbg(dev->dev, " designware: play supported\n");
 		idx = COMP1_TX_WORDSIZE_0(comp1);
@@ -503,7 +544,7 @@
 				   struct resource *res,
 				   const struct i2s_platform_data *pdata)
 {
-	u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
+	u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1);
 	u32 idx = COMP1_APB_DATA_WIDTH(comp1);
 	int ret;
 
@@ -607,6 +648,14 @@
 	if (pdata) {
 		dev->capability = pdata->cap;
 		clk_id = NULL;
+		dev->quirks = pdata->quirks;
+		if (dev->quirks & DW_I2S_QUIRK_COMP_REG_OFFSET) {
+			dev->i2s_reg_comp1 = pdata->i2s_reg_comp1;
+			dev->i2s_reg_comp2 = pdata->i2s_reg_comp2;
+		} else {
+			dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
+			dev->i2s_reg_comp2 = I2S_COMP_PARAM_2;
+		}
 		ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata);
 	} else {
 		clk_id = "i2sclk";
@@ -649,7 +698,7 @@
 			goto err_clk_disable;
 		}
 	}
-
+	pm_runtime_enable(&pdev->dev);
 	return 0;
 
 err_clk_disable:
@@ -665,6 +714,7 @@
 	if (dev->capability & DW_I2S_MASTER)
 		clk_disable_unprepare(dev->clk);
 
+	pm_runtime_disable(&pdev->dev);
 	return 0;
 }
 
@@ -677,12 +727,17 @@
 MODULE_DEVICE_TABLE(of, dw_i2s_of_match);
 #endif
 
+static const struct dev_pm_ops dwc_pm_ops = {
+	SET_RUNTIME_PM_OPS(dw_i2s_runtime_suspend, dw_i2s_runtime_resume, NULL)
+};
+
 static struct platform_driver dw_i2s_driver = {
 	.probe		= dw_i2s_probe,
 	.remove		= dw_i2s_remove,
 	.driver		= {
 		.name	= "designware-i2s",
 		.of_match_table = of_match_ptr(dw_i2s_of_match),
+		.pm = &dwc_pm_ops,
 	},
 };
 
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 1b05d1c..562b3bd 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -107,6 +107,13 @@
 	{"CPU-Capture",  NULL, "Capture"},
 };
 
+static const struct snd_soc_dapm_route audio_map_ac97[] = {
+	{"AC97 Playback",  NULL, "ASRC-Playback"},
+	{"Playback",  NULL, "AC97 Playback"},
+	{"ASRC-Capture",  NULL, "AC97 Capture"},
+	{"AC97 Capture",  NULL, "Capture"},
+};
+
 /* Add all possible widgets into here without being redundant */
 static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = {
 	SND_SOC_DAPM_LINE("Line Out Jack", NULL),
@@ -222,12 +229,15 @@
 					enum snd_soc_bias_level level)
 {
 	struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
-	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *codec_dai;
 	struct codec_priv *codec_priv = &priv->codec_priv;
 	struct device *dev = card->dev;
 	unsigned int pll_out;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+	codec_dai = rtd->codec_dai;
 	if (dapm->dev != codec_dai->dev)
 		return 0;
 
@@ -414,14 +424,16 @@
 static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
 {
 	struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
-	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct snd_soc_pcm_runtime *rtd = list_first_entry(
+			&card->rtd_list, struct snd_soc_pcm_runtime, list);
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct codec_priv *codec_priv = &priv->codec_priv;
 	struct device *dev = card->dev;
 	int ret;
 
 	if (fsl_asoc_card_is_ac97(priv)) {
 #if IS_ENABLED(CONFIG_SND_AC97_CODEC)
-		struct snd_soc_codec *codec = card->rtd[0].codec;
+		struct snd_soc_codec *codec = rtd->codec;
 		struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
 
 		/*
@@ -574,7 +586,8 @@
 	priv->card.dev = &pdev->dev;
 	priv->card.name = priv->name;
 	priv->card.dai_link = priv->dai_link;
-	priv->card.dapm_routes = audio_map;
+	priv->card.dapm_routes = fsl_asoc_card_is_ac97(priv) ?
+				 audio_map_ac97 : audio_map;
 	priv->card.late_probe = fsl_asoc_card_late_probe;
 	priv->card.num_dapm_routes = ARRAY_SIZE(audio_map);
 	priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets;
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 9f087d4..c1a0e01 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -31,21 +31,21 @@
 	dev_dbg(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
 
 /* Sample rates are aligned with that defined in pcm.h file */
-static const u8 process_option[][8][2] = {
-	/* 32kHz 44.1kHz 48kHz   64kHz   88.2kHz 96kHz   176kHz  192kHz */
-	{{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},	/* 5512Hz */
-	{{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},	/* 8kHz */
-	{{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},	/* 11025Hz */
-	{{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},	/* 16kHz */
-	{{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},	/* 22050Hz */
-	{{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},},	/* 32kHz */
-	{{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},},	/* 44.1kHz */
-	{{0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},},	/* 48kHz */
-	{{1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},},	/* 64kHz */
-	{{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},},	/* 88.2kHz */
-	{{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},},	/* 96kHz */
-	{{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},},	/* 176kHz */
-	{{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},},	/* 192kHz */
+static const u8 process_option[][12][2] = {
+	/* 8kHz 11.025kHz 16kHz 22.05kHz 32kHz 44.1kHz 48kHz   64kHz   88.2kHz 96kHz   176kHz  192kHz */
+	{{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},	/* 5512Hz */
+	{{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},	/* 8kHz */
+	{{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},	/* 11025Hz */
+	{{1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},	/* 16kHz */
+	{{1, 2}, {1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},},	/* 22050Hz */
+	{{1, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},},	/* 32kHz */
+	{{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},},	/* 44.1kHz */
+	{{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},},	/* 48kHz */
+	{{2, 2}, {2, 2}, {2, 2}, {2, 1}, {1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},},	/* 64kHz */
+	{{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},},	/* 88.2kHz */
+	{{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},},	/* 96kHz */
+	{{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},},	/* 176kHz */
+	{{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},},	/* 192kHz */
 };
 
 /* Corresponding to process_option */
@@ -55,7 +55,7 @@
 };
 
 static int supported_asrc_rate[] = {
-	32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000,
+	8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000,
 };
 
 /**
@@ -286,6 +286,13 @@
 		return -EINVAL;
 	}
 
+	if ((outrate > 8000 && outrate < 30000) &&
+	    (outrate/inrate > 24 || inrate/outrate > 8)) {
+		pair_err("exceed supported ratio range [1/24, 8] for \
+				inrate/outrate: %d/%d\n", inrate, outrate);
+		return -EINVAL;
+	}
+
 	/* Validate input and output clock sources */
 	clk_index[IN] = clk_map[IN][config->inclk];
 	clk_index[OUT] = clk_map[OUT][config->outclk];
@@ -447,7 +454,7 @@
 				  struct snd_soc_dai *dai)
 {
 	struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai);
-	int width = snd_pcm_format_width(params_format(params));
+	int width = params_width(params);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct fsl_asrc_pair *pair = runtime->private_data;
 	unsigned int channels = params_channels(params);
@@ -859,6 +866,10 @@
 		return PTR_ERR(asrc_priv->ipg_clk);
 	}
 
+	asrc_priv->spba_clk = devm_clk_get(&pdev->dev, "spba");
+	if (IS_ERR(asrc_priv->spba_clk))
+		dev_warn(&pdev->dev, "failed to get spba clock\n");
+
 	for (i = 0; i < ASRC_CLK_MAX_NUM; i++) {
 		sprintf(tmp, "asrck_%x", i);
 		asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp);
@@ -939,6 +950,11 @@
 	ret = clk_prepare_enable(asrc_priv->ipg_clk);
 	if (ret)
 		goto disable_mem_clk;
+	if (!IS_ERR(asrc_priv->spba_clk)) {
+		ret = clk_prepare_enable(asrc_priv->spba_clk);
+		if (ret)
+			goto disable_ipg_clk;
+	}
 	for (i = 0; i < ASRC_CLK_MAX_NUM; i++) {
 		ret = clk_prepare_enable(asrc_priv->asrck_clk[i]);
 		if (ret)
@@ -950,6 +966,9 @@
 disable_asrck_clk:
 	for (i--; i >= 0; i--)
 		clk_disable_unprepare(asrc_priv->asrck_clk[i]);
+	if (!IS_ERR(asrc_priv->spba_clk))
+		clk_disable_unprepare(asrc_priv->spba_clk);
+disable_ipg_clk:
 	clk_disable_unprepare(asrc_priv->ipg_clk);
 disable_mem_clk:
 	clk_disable_unprepare(asrc_priv->mem_clk);
@@ -963,6 +982,8 @@
 
 	for (i = 0; i < ASRC_CLK_MAX_NUM; i++)
 		clk_disable_unprepare(asrc_priv->asrck_clk[i]);
+	if (!IS_ERR(asrc_priv->spba_clk))
+		clk_disable_unprepare(asrc_priv->spba_clk);
 	clk_disable_unprepare(asrc_priv->ipg_clk);
 	clk_disable_unprepare(asrc_priv->mem_clk);
 
@@ -975,6 +996,9 @@
 {
 	struct fsl_asrc *asrc_priv = dev_get_drvdata(dev);
 
+	regmap_read(asrc_priv->regmap, REG_ASRCFG,
+		    &asrc_priv->regcache_cfg);
+
 	regcache_cache_only(asrc_priv->regmap, true);
 	regcache_mark_dirty(asrc_priv->regmap);
 
@@ -995,6 +1019,10 @@
 	regcache_cache_only(asrc_priv->regmap, false);
 	regcache_sync(asrc_priv->regmap);
 
+	regmap_update_bits(asrc_priv->regmap, REG_ASRCFG,
+			   ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK |
+			   ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg);
+
 	/* Restart enabled pairs */
 	regmap_update_bits(asrc_priv->regmap, REG_ASRCTR,
 			   ASRCTR_ASRCEi_ALL_MASK, asrctr);
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h
index 4aed63c..0f163ab 100644
--- a/sound/soc/fsl/fsl_asrc.h
+++ b/sound/soc/fsl/fsl_asrc.h
@@ -132,10 +132,13 @@
 #define ASRCFG_INIRQi			(1 << ASRCFG_INIRQi_SHIFT(i))
 #define ASRCFG_NDPRi_SHIFT(i)		(18 + i)
 #define ASRCFG_NDPRi_MASK(i)		(1 << ASRCFG_NDPRi_SHIFT(i))
+#define ASRCFG_NDPRi_ALL_SHIFT		18
+#define ASRCFG_NDPRi_ALL_MASK		(7 << ASRCFG_NDPRi_ALL_SHIFT)
 #define ASRCFG_NDPRi			(1 << ASRCFG_NDPRi_SHIFT(i))
 #define ASRCFG_POSTMODi_SHIFT(i)	(8 + (i << 2))
 #define ASRCFG_POSTMODi_WIDTH		2
 #define ASRCFG_POSTMODi_MASK(i)		(((1 << ASRCFG_POSTMODi_WIDTH) - 1) << ASRCFG_POSTMODi_SHIFT(i))
+#define ASRCFG_POSTMODi_ALL_MASK	(ASRCFG_POSTMODi_MASK(0) | ASRCFG_POSTMODi_MASK(1) | ASRCFG_POSTMODi_MASK(2))
 #define ASRCFG_POSTMOD(i, v)		((v) << ASRCFG_POSTMODi_SHIFT(i))
 #define ASRCFG_POSTMODi_UP(i)		(0 << ASRCFG_POSTMODi_SHIFT(i))
 #define ASRCFG_POSTMODi_DCON(i)		(1 << ASRCFG_POSTMODi_SHIFT(i))
@@ -143,6 +146,7 @@
 #define ASRCFG_PREMODi_SHIFT(i)		(6 + (i << 2))
 #define ASRCFG_PREMODi_WIDTH		2
 #define ASRCFG_PREMODi_MASK(i)		(((1 << ASRCFG_PREMODi_WIDTH) - 1) << ASRCFG_PREMODi_SHIFT(i))
+#define ASRCFG_PREMODi_ALL_MASK		(ASRCFG_PREMODi_MASK(0) | ASRCFG_PREMODi_MASK(1) | ASRCFG_PREMODi_MASK(2))
 #define ASRCFG_PREMOD(i, v)		((v) << ASRCFG_PREMODi_SHIFT(i))
 #define ASRCFG_PREMODi_UP(i)		(0 << ASRCFG_PREMODi_SHIFT(i))
 #define ASRCFG_PREMODi_DCON(i)		(1 << ASRCFG_PREMODi_SHIFT(i))
@@ -426,6 +430,7 @@
  * @paddr: physical address to the base address of registers
  * @mem_clk: clock source to access register
  * @ipg_clk: clock source to drive peripheral
+ * @spba_clk: SPBA clock (optional, depending on SoC design)
  * @asrck_clk: clock sources to driver ASRC internal logic
  * @lock: spin lock for resource protection
  * @pair: pair pointers
@@ -433,6 +438,7 @@
  * @channel_avail: non-occupied channel numbers
  * @asrc_rate: default sample rate for ASoC Back-Ends
  * @asrc_width: default sample width for ASoC Back-Ends
+ * @regcache_cfg: store register value of REG_ASRCFG
  */
 struct fsl_asrc {
 	struct snd_dmaengine_dai_dma_data dma_params_rx;
@@ -442,6 +448,7 @@
 	unsigned long paddr;
 	struct clk *mem_clk;
 	struct clk *ipg_clk;
+	struct clk *spba_clk;
 	struct clk *asrck_clk[ASRC_CLK_MAX_NUM];
 	spinlock_t lock;
 
@@ -451,6 +458,8 @@
 
 	int asrc_rate;
 	int asrc_width;
+
+	u32 regcache_cfg;
 };
 
 extern struct snd_soc_platform_driver fsl_asrc_platform;
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 59f234e..26a90e1 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -35,6 +35,7 @@
  * @coreclk: clock source to access register
  * @extalclk: esai clock source to derive HCK, SCK and FS
  * @fsysclk: system clock source to derive HCK, SCK and FS
+ * @spbaclk: SPBA clock (optional, depending on SoC design)
  * @fifo_depth: depth of tx/rx FIFO
  * @slot_width: width of each DAI slot
  * @slots: number of slots
@@ -54,6 +55,7 @@
 	struct clk *coreclk;
 	struct clk *extalclk;
 	struct clk *fsysclk;
+	struct clk *spbaclk;
 	u32 fifo_depth;
 	u32 slot_width;
 	u32 slots;
@@ -469,6 +471,11 @@
 	ret = clk_prepare_enable(esai_priv->coreclk);
 	if (ret)
 		return ret;
+	if (!IS_ERR(esai_priv->spbaclk)) {
+		ret = clk_prepare_enable(esai_priv->spbaclk);
+		if (ret)
+			goto err_spbaclk;
+	}
 	if (!IS_ERR(esai_priv->extalclk)) {
 		ret = clk_prepare_enable(esai_priv->extalclk);
 		if (ret)
@@ -499,6 +506,9 @@
 	if (!IS_ERR(esai_priv->extalclk))
 		clk_disable_unprepare(esai_priv->extalclk);
 err_extalck:
+	if (!IS_ERR(esai_priv->spbaclk))
+		clk_disable_unprepare(esai_priv->spbaclk);
+err_spbaclk:
 	clk_disable_unprepare(esai_priv->coreclk);
 
 	return ret;
@@ -510,7 +520,7 @@
 {
 	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
 	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-	u32 width = snd_pcm_format_width(params_format(params));
+	u32 width = params_width(params);
 	u32 channels = params_channels(params);
 	u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
 	u32 slot_width = width;
@@ -564,6 +574,8 @@
 		clk_disable_unprepare(esai_priv->fsysclk);
 	if (!IS_ERR(esai_priv->extalclk))
 		clk_disable_unprepare(esai_priv->extalclk);
+	if (!IS_ERR(esai_priv->spbaclk))
+		clk_disable_unprepare(esai_priv->spbaclk);
 	clk_disable_unprepare(esai_priv->coreclk);
 }
 
@@ -653,21 +665,28 @@
 };
 
 static const struct reg_default fsl_esai_reg_defaults[] = {
-	{0x8,  0x00000000},
-	{0x10, 0x00000000},
-	{0x18, 0x00000000},
-	{0x98, 0x00000000},
-	{0xd0, 0x00000000},
-	{0xd4, 0x00000000},
-	{0xd8, 0x00000000},
-	{0xdc, 0x00000000},
-	{0xe0, 0x00000000},
-	{0xe4, 0x0000ffff},
-	{0xe8, 0x0000ffff},
-	{0xec, 0x0000ffff},
-	{0xf0, 0x0000ffff},
-	{0xf8, 0x00000000},
-	{0xfc, 0x00000000},
+	{REG_ESAI_ETDR,	 0x00000000},
+	{REG_ESAI_ECR,	 0x00000000},
+	{REG_ESAI_TFCR,	 0x00000000},
+	{REG_ESAI_RFCR,	 0x00000000},
+	{REG_ESAI_TX0,	 0x00000000},
+	{REG_ESAI_TX1,	 0x00000000},
+	{REG_ESAI_TX2,	 0x00000000},
+	{REG_ESAI_TX3,	 0x00000000},
+	{REG_ESAI_TX4,	 0x00000000},
+	{REG_ESAI_TX5,	 0x00000000},
+	{REG_ESAI_TSR,	 0x00000000},
+	{REG_ESAI_SAICR, 0x00000000},
+	{REG_ESAI_TCR,	 0x00000000},
+	{REG_ESAI_TCCR,	 0x00000000},
+	{REG_ESAI_RCR,	 0x00000000},
+	{REG_ESAI_RCCR,	 0x00000000},
+	{REG_ESAI_TSMA,  0x0000ffff},
+	{REG_ESAI_TSMB,  0x0000ffff},
+	{REG_ESAI_RSMA,  0x0000ffff},
+	{REG_ESAI_RSMB,  0x0000ffff},
+	{REG_ESAI_PRRC,  0x00000000},
+	{REG_ESAI_PCRC,  0x00000000},
 };
 
 static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
@@ -705,17 +724,10 @@
 static bool fsl_esai_volatile_reg(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
-	case REG_ESAI_ETDR:
 	case REG_ESAI_ERDR:
 	case REG_ESAI_ESR:
 	case REG_ESAI_TFSR:
 	case REG_ESAI_RFSR:
-	case REG_ESAI_TX0:
-	case REG_ESAI_TX1:
-	case REG_ESAI_TX2:
-	case REG_ESAI_TX3:
-	case REG_ESAI_TX4:
-	case REG_ESAI_TX5:
 	case REG_ESAI_RX0:
 	case REG_ESAI_RX1:
 	case REG_ESAI_RX2:
@@ -819,6 +831,11 @@
 		dev_warn(&pdev->dev, "failed to get fsys clock: %ld\n",
 				PTR_ERR(esai_priv->fsysclk));
 
+	esai_priv->spbaclk = devm_clk_get(&pdev->dev, "spba");
+	if (IS_ERR(esai_priv->spbaclk))
+		dev_warn(&pdev->dev, "failed to get spba clock: %ld\n",
+				PTR_ERR(esai_priv->spbaclk));
+
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
 		dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 08b460b..fef264d 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -126,6 +126,17 @@
 		return IRQ_HANDLED;
 }
 
+static int fsl_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
+				u32 rx_mask, int slots, int slot_width)
+{
+	struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+	sai->slots = slots;
+	sai->slot_width = slot_width;
+
+	return 0;
+}
+
 static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
 		int clk_id, unsigned int freq, int fsl_dir)
 {
@@ -354,13 +365,25 @@
 		return -EINVAL;
 	}
 
-	if ((tx && sai->synchronous[TX]) || (!tx && !sai->synchronous[RX])) {
+	/*
+	 * 1) For Asynchronous mode, we must set RCR2 register for capture, and
+	 *    set TCR2 register for playback.
+	 * 2) For Tx sync with Rx clock, we must set RCR2 register for playback
+	 *    and capture.
+	 * 3) For Rx sync with Tx clock, we must set TCR2 register for playback
+	 *    and capture.
+	 * 4) For Tx and Rx are both Synchronous with another SAI, we just
+	 *    ignore it.
+	 */
+	if ((sai->synchronous[TX] && !sai->synchronous[RX]) ||
+	    (!tx && !sai->synchronous[RX])) {
 		regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
 				   FSL_SAI_CR2_MSEL_MASK,
 				   FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
 		regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
 				   FSL_SAI_CR2_DIV_MASK, savediv - 1);
-	} else {
+	} else if ((sai->synchronous[RX] && !sai->synchronous[TX]) ||
+		   (tx && !sai->synchronous[TX])) {
 		regmap_update_bits(sai->regmap, FSL_SAI_TCR2,
 				   FSL_SAI_CR2_MSEL_MASK,
 				   FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
@@ -381,13 +404,21 @@
 	struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
 	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 	unsigned int channels = params_channels(params);
-	u32 word_width = snd_pcm_format_width(params_format(params));
+	u32 word_width = params_width(params);
 	u32 val_cr4 = 0, val_cr5 = 0;
+	u32 slots = (channels == 1) ? 2 : channels;
+	u32 slot_width = word_width;
 	int ret;
 
+	if (sai->slots)
+		slots = sai->slots;
+
+	if (sai->slot_width)
+		slot_width = sai->slot_width;
+
 	if (!sai->is_slave_mode) {
 		ret = fsl_sai_set_bclk(cpu_dai, tx,
-			2 * word_width * params_rate(params));
+				slots * slot_width * params_rate(params));
 		if (ret)
 			return ret;
 
@@ -399,21 +430,49 @@
 
 			sai->mclk_streams |= BIT(substream->stream);
 		}
-
 	}
 
 	if (!sai->is_dsp_mode)
-		val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
+		val_cr4 |= FSL_SAI_CR4_SYWD(slot_width);
 
-	val_cr5 |= FSL_SAI_CR5_WNW(word_width);
-	val_cr5 |= FSL_SAI_CR5_W0W(word_width);
+	val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
+	val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
 
 	if (sai->is_lsb_first)
 		val_cr5 |= FSL_SAI_CR5_FBT(0);
 	else
 		val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
 
-	val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
+	val_cr4 |= FSL_SAI_CR4_FRSZ(slots);
+
+	/*
+	 * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will
+	 * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4),
+	 * RCR5(TCR5) and RMR(TMR) for playback(capture), or there will be sync
+	 * error.
+	 */
+
+	if (!sai->is_slave_mode) {
+		if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
+			regmap_update_bits(sai->regmap, FSL_SAI_TCR4,
+				FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+				val_cr4);
+			regmap_update_bits(sai->regmap, FSL_SAI_TCR5,
+				FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+				FSL_SAI_CR5_FBT_MASK, val_cr5);
+			regmap_write(sai->regmap, FSL_SAI_TMR,
+				~0UL - ((1 << channels) - 1));
+		} else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
+			regmap_update_bits(sai->regmap, FSL_SAI_RCR4,
+				FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+				val_cr4);
+			regmap_update_bits(sai->regmap, FSL_SAI_RCR5,
+				FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
+				FSL_SAI_CR5_FBT_MASK, val_cr5);
+			regmap_write(sai->regmap, FSL_SAI_RMR,
+				~0UL - ((1 << channels) - 1));
+		}
+	}
 
 	regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
 			   FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
@@ -569,6 +628,7 @@
 static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
 	.set_sysclk	= fsl_sai_set_dai_sysclk,
 	.set_fmt	= fsl_sai_set_dai_fmt,
+	.set_tdm_slot	= fsl_sai_set_dai_tdm_slot,
 	.hw_params	= fsl_sai_hw_params,
 	.hw_free	= fsl_sai_hw_free,
 	.trigger	= fsl_sai_trigger,
@@ -627,6 +687,22 @@
 	.name           = "fsl-sai",
 };
 
+static struct reg_default fsl_sai_reg_defaults[] = {
+	{FSL_SAI_TCR1, 0},
+	{FSL_SAI_TCR2, 0},
+	{FSL_SAI_TCR3, 0},
+	{FSL_SAI_TCR4, 0},
+	{FSL_SAI_TCR5, 0},
+	{FSL_SAI_TDR,  0},
+	{FSL_SAI_TMR,  0},
+	{FSL_SAI_RCR1, 0},
+	{FSL_SAI_RCR2, 0},
+	{FSL_SAI_RCR3, 0},
+	{FSL_SAI_RCR4, 0},
+	{FSL_SAI_RCR5, 0},
+	{FSL_SAI_RMR,  0},
+};
+
 static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
@@ -660,13 +736,11 @@
 	case FSL_SAI_RCSR:
 	case FSL_SAI_TFR:
 	case FSL_SAI_RFR:
-	case FSL_SAI_TDR:
 	case FSL_SAI_RDR:
 		return true;
 	default:
 		return false;
 	}
-
 }
 
 static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
@@ -699,6 +773,8 @@
 	.val_bits = 32,
 
 	.max_register = FSL_SAI_RMR,
+	.reg_defaults = fsl_sai_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults),
 	.readable_reg = fsl_sai_readable_reg,
 	.volatile_reg = fsl_sai_volatile_reg,
 	.writeable_reg = fsl_sai_writeable_reg,
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index b95fbc3..d9ed7be 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -143,6 +143,9 @@
 
 	unsigned int mclk_id[2];
 	unsigned int mclk_streams;
+	unsigned int slots;
+	unsigned int slot_width;
+
 	struct snd_dmaengine_dai_dma_data dma_params_rx;
 	struct snd_dmaengine_dai_dma_data dma_params_tx;
 };
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 3d59bb6..151849f 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -88,6 +88,7 @@
  * @rxclk: rx clock sources for capture
  * @coreclk: core clock for register access via DMA
  * @sysclk: system clock for rx clock rate measurement
+ * @spbaclk: SPBA clock (optional, depending on SoC design)
  * @dma_params_tx: DMA parameters for transmit channel
  * @dma_params_rx: DMA parameters for receive channel
  */
@@ -106,6 +107,7 @@
 	struct clk *rxclk;
 	struct clk *coreclk;
 	struct clk *sysclk;
+	struct clk *spbaclk;
 	struct snd_dmaengine_dai_dma_data dma_params_tx;
 	struct snd_dmaengine_dai_dma_data dma_params_rx;
 	/* regcache for SRPC */
@@ -474,6 +476,14 @@
 			return ret;
 		}
 
+		if (!IS_ERR(spdif_priv->spbaclk)) {
+			ret = clk_prepare_enable(spdif_priv->spbaclk);
+			if (ret) {
+				dev_err(&pdev->dev, "failed to enable spba clock\n");
+				goto err_spbaclk;
+			}
+		}
+
 		ret = spdif_softreset(spdif_priv);
 		if (ret) {
 			dev_err(&pdev->dev, "failed to soft reset\n");
@@ -515,6 +525,9 @@
 	for (i--; i >= 0; i--)
 		clk_disable_unprepare(spdif_priv->txclk[i]);
 err:
+	if (!IS_ERR(spdif_priv->spbaclk))
+		clk_disable_unprepare(spdif_priv->spbaclk);
+err_spbaclk:
 	clk_disable_unprepare(spdif_priv->coreclk);
 
 	return ret;
@@ -548,6 +561,8 @@
 		spdif_intr_status_clear(spdif_priv);
 		regmap_update_bits(regmap, REG_SPDIF_SCR,
 				SCR_LOW_POWER, SCR_LOW_POWER);
+		if (!IS_ERR(spdif_priv->spbaclk))
+			clk_disable_unprepare(spdif_priv->spbaclk);
 		clk_disable_unprepare(spdif_priv->coreclk);
 	}
 }
@@ -1006,12 +1021,14 @@
 
 /* FSL SPDIF REGMAP */
 static const struct reg_default fsl_spdif_reg_defaults[] = {
-	{0x0,  0x00000400},
-	{0x4,  0x00000000},
-	{0xc,  0x00000000},
-	{0x34, 0x00000000},
-	{0x38, 0x00000000},
-	{0x50, 0x00020f00},
+	{REG_SPDIF_SCR,    0x00000400},
+	{REG_SPDIF_SRCD,   0x00000000},
+	{REG_SPDIF_SIE,	   0x00000000},
+	{REG_SPDIF_STL,	   0x00000000},
+	{REG_SPDIF_STR,	   0x00000000},
+	{REG_SPDIF_STCSCH, 0x00000000},
+	{REG_SPDIF_STCSCL, 0x00000000},
+	{REG_SPDIF_STC,	   0x00020f00},
 };
 
 static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
@@ -1049,8 +1066,6 @@
 	case REG_SPDIF_SRCSL:
 	case REG_SPDIF_SRU:
 	case REG_SPDIF_SRQ:
-	case REG_SPDIF_STL:
-	case REG_SPDIF_STR:
 	case REG_SPDIF_SRFM:
 		return true;
 	default:
@@ -1261,6 +1276,10 @@
 		return PTR_ERR(spdif_priv->coreclk);
 	}
 
+	spdif_priv->spbaclk = devm_clk_get(&pdev->dev, "spba");
+	if (IS_ERR(spdif_priv->spbaclk))
+		dev_warn(&pdev->dev, "no spba clock in devicetree\n");
+
 	/* Select clock source for rx/tx clock */
 	spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1");
 	if (IS_ERR(spdif_priv->rxclk)) {
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 95d2392..40dfd8a 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -113,17 +113,17 @@
 };
 
 static const struct reg_default fsl_ssi_reg_defaults[] = {
-	{0x10, 0x00000000},
-	{0x18, 0x00003003},
-	{0x1c, 0x00000200},
-	{0x20, 0x00000200},
-	{0x24, 0x00040000},
-	{0x28, 0x00040000},
-	{0x38, 0x00000000},
-	{0x48, 0x00000000},
-	{0x4c, 0x00000000},
-	{0x54, 0x00000000},
-	{0x58, 0x00000000},
+	{CCSR_SSI_SCR,     0x00000000},
+	{CCSR_SSI_SIER,    0x00003003},
+	{CCSR_SSI_STCR,    0x00000200},
+	{CCSR_SSI_SRCR,    0x00000200},
+	{CCSR_SSI_STCCR,   0x00040000},
+	{CCSR_SSI_SRCCR,   0x00040000},
+	{CCSR_SSI_SACNT,   0x00000000},
+	{CCSR_SSI_STMSK,   0x00000000},
+	{CCSR_SSI_SRMSK,   0x00000000},
+	{CCSR_SSI_SACCEN,  0x00000000},
+	{CCSR_SSI_SACCDIS, 0x00000000},
 };
 
 static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg)
@@ -146,6 +146,7 @@
 	case CCSR_SSI_SRX1:
 	case CCSR_SSI_SISR:
 	case CCSR_SSI_SFCSR:
+	case CCSR_SSI_SACNT:
 	case CCSR_SSI_SACADD:
 	case CCSR_SSI_SACDAT:
 	case CCSR_SSI_SATAG:
@@ -156,6 +157,21 @@
 	}
 }
 
+static bool fsl_ssi_precious_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case CCSR_SSI_SRX0:
+	case CCSR_SSI_SRX1:
+	case CCSR_SSI_SISR:
+	case CCSR_SSI_SACADD:
+	case CCSR_SSI_SACDAT:
+	case CCSR_SSI_SATAG:
+		return true;
+	default:
+		return false;
+	}
+}
+
 static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
@@ -178,6 +194,7 @@
 	.num_reg_defaults = ARRAY_SIZE(fsl_ssi_reg_defaults),
 	.readable_reg = fsl_ssi_readable_reg,
 	.volatile_reg = fsl_ssi_volatile_reg,
+	.precious_reg = fsl_ssi_precious_reg,
 	.writeable_reg = fsl_ssi_writeable_reg,
 	.cache_type = REGCACHE_RBTREE,
 };
@@ -239,8 +256,9 @@
 	unsigned int baudclk_streams;
 	unsigned int bitclk_freq;
 
-	/*regcache for SFCSR*/
+	/* regcache for volatile regs */
 	u32 regcache_sfcsr;
+	u32 regcache_sacnt;
 
 	/* DMA params */
 	struct snd_dmaengine_dai_dma_data dma_params_tx;
@@ -767,8 +785,7 @@
 	struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
 	struct regmap *regs = ssi_private->regs;
 	unsigned int channels = params_channels(hw_params);
-	unsigned int sample_size =
-		snd_pcm_format_width(params_format(hw_params));
+	unsigned int sample_size = params_width(hw_params);
 	u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
 	int ret;
 	u32 scr_val;
@@ -1588,6 +1605,8 @@
 
 	regmap_read(regs, CCSR_SSI_SFCSR,
 			&ssi_private->regcache_sfcsr);
+	regmap_read(regs, CCSR_SSI_SACNT,
+			&ssi_private->regcache_sacnt);
 
 	regcache_cache_only(regs, true);
 	regcache_mark_dirty(regs);
@@ -1606,6 +1625,8 @@
 			CCSR_SSI_SFCSR_RFWM1_MASK | CCSR_SSI_SFCSR_TFWM1_MASK |
 			CCSR_SSI_SFCSR_RFWM0_MASK | CCSR_SSI_SFCSR_TFWM0_MASK,
 			ssi_private->regcache_sfcsr);
+	regmap_write(regs, CCSR_SSI_SACNT,
+			ssi_private->regcache_sacnt);
 
 	return regcache_sync(regs);
 }
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
index 1fc01ed..f3d3d1f 100644
--- a/sound/soc/fsl/imx-pcm-dma.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -62,6 +62,8 @@
 
 	config = devm_kzalloc(&pdev->dev,
 			sizeof(struct snd_dmaengine_pcm_config), GFP_KERNEL);
+	if (!config)
+		return -ENOMEM;
 	*config = imx_dmaengine_pcm_config;
 	if (size)
 		config->prealloc_buffer_size = size;
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 7abf6a0..49d7513 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -220,9 +220,9 @@
 	ret = dma_mmap_writecombine(substream->pcm->card->dev, vma,
 		runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
 
-	pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
+	pr_debug("%s: ret: %d %p %pad 0x%08x\n", __func__, ret,
 			runtime->dma_area,
-			runtime->dma_addr,
+			&runtime->dma_addr,
 			runtime->dma_bytes);
 	return ret;
 }
diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c
index b38b98c..201a70d 100644
--- a/sound/soc/fsl/imx-wm8962.c
+++ b/sound/soc/fsl/imx-wm8962.c
@@ -69,13 +69,16 @@
 					struct snd_soc_dapm_context *dapm,
 					enum snd_soc_bias_level level)
 {
-	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *codec_dai;
 	struct imx_priv *priv = &card_priv;
 	struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
 	struct device *dev = &priv->pdev->dev;
 	unsigned int pll_out;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+	codec_dai = rtd->codec_dai;
 	if (dapm->dev != codec_dai->dev)
 		return 0;
 
@@ -135,12 +138,15 @@
 
 static int imx_wm8962_late_probe(struct snd_soc_card *card)
 {
-	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *codec_dai;
 	struct imx_priv *priv = &card_priv;
 	struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
 	struct device *dev = &priv->pdev->dev;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+	codec_dai = rtd->codec_dai;
 	ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
 			data->clk_frequency, SND_SOC_CLOCK_IN);
 	if (ret < 0)
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 6f236f1..ddf49f3 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -189,8 +189,7 @@
 {
 	struct device *dev = pdev->dev.parent;
 	/* ssi_pdev is the platform device for the SSI node that probed us */
-	struct platform_device *ssi_pdev =
-		container_of(dev, struct platform_device, dev);
+	struct platform_device *ssi_pdev = to_platform_device(dev);
 	struct device_node *np = ssi_pdev->dev.of_node;
 	struct device_node *codec_np = NULL;
 	struct mpc8610_hpcd_data *machine_data;
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index 747aab0..a1f780e 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -199,8 +199,7 @@
 {
 	struct device *dev = pdev->dev.parent;
 	/* ssi_pdev is the platform device for the SSI node that probed us */
-	struct platform_device *ssi_pdev =
-		container_of(dev, struct platform_device, dev);
+	struct platform_device *ssi_pdev = to_platform_device(dev);
 	struct device_node *np = ssi_pdev->dev.of_node;
 	struct device_node *codec_np = NULL;
 	struct machine_data *mdata;
diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c
index 1dd49e5..d4d88a8 100644
--- a/sound/soc/fsl/p1022_rdk.c
+++ b/sound/soc/fsl/p1022_rdk.c
@@ -203,8 +203,7 @@
 {
 	struct device *dev = pdev->dev.parent;
 	/* ssi_pdev is the platform device for the SSI node that probed us */
-	struct platform_device *ssi_pdev =
-		container_of(dev, struct platform_device, dev);
+	struct platform_device *ssi_pdev = to_platform_device(dev);
 	struct device_node *np = ssi_pdev->dev.of_node;
 	struct device_node *codec_np = NULL;
 	struct machine_data *mdata;
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 54c3320..1ded881 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -45,7 +45,7 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);
 	struct simple_dai_props *dai_props =
-		&priv->dai_props[rtd - rtd->card->rtd];
+		&priv->dai_props[rtd->num];
 	int ret;
 
 	ret = clk_prepare_enable(dai_props->cpu_dai.clk);
@@ -64,7 +64,7 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);
 	struct simple_dai_props *dai_props =
-		&priv->dai_props[rtd - rtd->card->rtd];
+		&priv->dai_props[rtd->num];
 
 	clk_disable_unprepare(dai_props->cpu_dai.clk);
 
@@ -78,8 +78,7 @@
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
-	struct simple_dai_props *dai_props =
-		&priv->dai_props[rtd - rtd->card->rtd];
+	struct simple_dai_props *dai_props = &priv->dai_props[rtd->num];
 	unsigned int mclk, mclk_fs = 0;
 	int ret = 0;
 
@@ -174,10 +173,9 @@
 	struct snd_soc_dai *codec = rtd->codec_dai;
 	struct snd_soc_dai *cpu = rtd->cpu_dai;
 	struct simple_dai_props *dai_props;
-	int num, ret;
+	int ret;
 
-	num = rtd - rtd->card->rtd;
-	dai_props = &priv->dai_props[num];
+	dai_props = &priv->dai_props[rtd->num];
 	ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai);
 	if (ret < 0)
 		return ret;
diff --git a/sound/soc/img/Kconfig b/sound/soc/img/Kconfig
new file mode 100644
index 0000000..857a951
--- /dev/null
+++ b/sound/soc/img/Kconfig
@@ -0,0 +1,52 @@
+config SND_SOC_IMG
+	bool "Audio support for Imagination Technologies designs"
+	help
+	  Audio support for Imagination Technologies audio hardware
+
+config SND_SOC_IMG_I2S_IN
+	tristate "Imagination I2S Input Device Driver"
+	depends on SND_SOC_IMG
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	help
+	  Say Y or M if you want to add support for I2S in driver for
+	  Imagination Technologies I2S in device.
+
+config SND_SOC_IMG_I2S_OUT
+	tristate "Imagination I2S Output Device Driver"
+	depends on SND_SOC_IMG
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	help
+	  Say Y or M if you want to add support for I2S out driver for
+	  Imagination Technologies I2S out device.
+
+config SND_SOC_IMG_PARALLEL_OUT
+	tristate "Imagination Parallel Output Device Driver"
+	depends on SND_SOC_IMG
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	help
+	  Say Y or M if you want to add support for parallel out driver for
+	  Imagination Technologies parallel out device.
+
+config SND_SOC_IMG_SPDIF_IN
+	tristate "Imagination SPDIF Input Device Driver"
+	depends on SND_SOC_IMG
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	help
+	  Say Y or M if you want to add support for SPDIF input driver for
+	  Imagination Technologies SPDIF input device.
+
+config SND_SOC_IMG_SPDIF_OUT
+	tristate "Imagination SPDIF Output Device Driver"
+	depends on SND_SOC_IMG
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	help
+	  Say Y or M if you want to add support for SPDIF out driver for
+	  Imagination Technologies SPDIF out device.
+
+
+config SND_SOC_IMG_PISTACHIO_INTERNAL_DAC
+	tristate "Support for Pistachio SoC Internal DAC Driver"
+	depends on SND_SOC_IMG
+	help
+	  Say Y or M if you want to add support for Pistachio internal DAC
+	  driver for Imagination Technologies Pistachio internal DAC device.
diff --git a/sound/soc/img/Makefile b/sound/soc/img/Makefile
new file mode 100644
index 0000000..0508c1c
--- /dev/null
+++ b/sound/soc/img/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_SND_SOC_IMG_I2S_IN) += img-i2s-in.o
+obj-$(CONFIG_SND_SOC_IMG_I2S_OUT) += img-i2s-out.o
+obj-$(CONFIG_SND_SOC_IMG_PARALLEL_OUT) += img-parallel-out.o
+obj-$(CONFIG_SND_SOC_IMG_SPDIF_IN) += img-spdif-in.o
+obj-$(CONFIG_SND_SOC_IMG_SPDIF_OUT) += img-spdif-out.o
+
+obj-$(CONFIG_SND_SOC_IMG_PISTACHIO_INTERNAL_DAC) += pistachio-internal-dac.o
diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c
new file mode 100644
index 0000000..0389203
--- /dev/null
+++ b/sound/soc/img/img-i2s-in.c
@@ -0,0 +1,516 @@
+/*
+ * IMG I2S input controller driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define IMG_I2S_IN_RX_FIFO			0x0
+
+#define IMG_I2S_IN_CTL				0x4
+#define IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK		0xfffffffc
+#define IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT		2
+#define IMG_I2S_IN_CTL_16PACK_MASK		BIT(1)
+#define IMG_I2S_IN_CTL_ME_MASK			BIT(0)
+
+#define IMG_I2S_IN_CH_CTL			0x4
+#define IMG_I2S_IN_CH_CTL_CCDEL_MASK		0x38000
+#define IMG_I2S_IN_CH_CTL_CCDEL_SHIFT		15
+#define IMG_I2S_IN_CH_CTL_FEN_MASK		BIT(14)
+#define IMG_I2S_IN_CH_CTL_FMODE_MASK		BIT(13)
+#define IMG_I2S_IN_CH_CTL_16PACK_MASK		BIT(12)
+#define IMG_I2S_IN_CH_CTL_JUST_MASK		BIT(10)
+#define IMG_I2S_IN_CH_CTL_PACKH_MASK		BIT(9)
+#define IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK	BIT(8)
+#define IMG_I2S_IN_CH_CTL_BLKP_MASK		BIT(7)
+#define IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK	BIT(6)
+#define IMG_I2S_IN_CH_CTL_LRD_MASK		BIT(3)
+#define IMG_I2S_IN_CH_CTL_FW_MASK		BIT(2)
+#define IMG_I2S_IN_CH_CTL_SW_MASK		BIT(1)
+#define IMG_I2S_IN_CH_CTL_ME_MASK		BIT(0)
+
+#define IMG_I2S_IN_CH_STRIDE			0x20
+
+struct img_i2s_in {
+	void __iomem *base;
+	struct clk *clk_sys;
+	struct snd_dmaengine_dai_dma_data dma_data;
+	struct device *dev;
+	unsigned int max_i2s_chan;
+	void __iomem *channel_base;
+	unsigned int active_channels;
+	struct snd_soc_dai_driver dai_driver;
+};
+
+static inline void img_i2s_in_writel(struct img_i2s_in *i2s, u32 val, u32 reg)
+{
+	writel(val, i2s->base + reg);
+}
+
+static inline u32 img_i2s_in_readl(struct img_i2s_in *i2s, u32 reg)
+{
+	return readl(i2s->base + reg);
+}
+
+static inline void img_i2s_in_ch_writel(struct img_i2s_in *i2s, u32 chan,
+					u32 val, u32 reg)
+{
+	writel(val, i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg);
+}
+
+static inline u32 img_i2s_in_ch_readl(struct img_i2s_in *i2s, u32 chan,
+					u32 reg)
+{
+	return readl(i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg);
+}
+
+static inline void img_i2s_in_ch_disable(struct img_i2s_in *i2s, u32 chan)
+{
+	u32 reg;
+
+	reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL);
+	reg &= ~IMG_I2S_IN_CH_CTL_ME_MASK;
+	img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL);
+}
+
+static inline void img_i2s_in_ch_enable(struct img_i2s_in *i2s, u32 chan)
+{
+	u32 reg;
+
+	reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL);
+	reg |= IMG_I2S_IN_CH_CTL_ME_MASK;
+	img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL);
+}
+
+static inline void img_i2s_in_disable(struct img_i2s_in *i2s)
+{
+	u32 reg;
+
+	reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
+	reg &= ~IMG_I2S_IN_CTL_ME_MASK;
+	img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL);
+}
+
+static inline void img_i2s_in_enable(struct img_i2s_in *i2s)
+{
+	u32 reg;
+
+	reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
+	reg |= IMG_I2S_IN_CTL_ME_MASK;
+	img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL);
+}
+
+static inline void img_i2s_in_flush(struct img_i2s_in *i2s)
+{
+	int i;
+	u32 reg;
+
+	for (i = 0; i < i2s->active_channels; i++) {
+		reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
+		reg |= IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK;
+		img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+		reg &= ~IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK;
+		img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+	}
+}
+
+static int img_i2s_in_trigger(struct snd_pcm_substream *substream, int cmd,
+	struct snd_soc_dai *dai)
+{
+	struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		img_i2s_in_enable(i2s);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		img_i2s_in_disable(i2s);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int img_i2s_in_check_rate(struct img_i2s_in *i2s,
+		unsigned int sample_rate, unsigned int frame_size,
+		unsigned int *bclk_filter_enable,
+		unsigned int *bclk_filter_value)
+{
+	unsigned int bclk_freq, cur_freq;
+
+	bclk_freq = sample_rate * frame_size;
+
+	cur_freq = clk_get_rate(i2s->clk_sys);
+
+	if (cur_freq >= bclk_freq * 8) {
+		*bclk_filter_enable = 1;
+		*bclk_filter_value = 0;
+	} else if (cur_freq >= bclk_freq * 7) {
+		*bclk_filter_enable = 1;
+		*bclk_filter_value = 1;
+	} else if (cur_freq >= bclk_freq * 6) {
+		*bclk_filter_enable = 0;
+		*bclk_filter_value = 0;
+	} else {
+		dev_err(i2s->dev,
+			"Sys clock rate %u insufficient for sample rate %u\n",
+			cur_freq, sample_rate);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int img_i2s_in_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
+	unsigned int rate, channels, i2s_channels, frame_size;
+	unsigned int bclk_filter_enable, bclk_filter_value;
+	int i, ret = 0;
+	u32 reg, control_mask, chan_control_mask;
+	u32 control_set = 0, chan_control_set = 0;
+	snd_pcm_format_t format;
+
+	rate = params_rate(params);
+	format = params_format(params);
+	channels = params_channels(params);
+	i2s_channels = channels / 2;
+
+	switch (format) {
+	case SNDRV_PCM_FORMAT_S32_LE:
+		frame_size = 64;
+		chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK;
+		chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK;
+		chan_control_set |= IMG_I2S_IN_CH_CTL_PACKH_MASK;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		frame_size = 64;
+		chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK;
+		chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		frame_size = 32;
+		control_set |= IMG_I2S_IN_CTL_16PACK_MASK;
+		chan_control_set |= IMG_I2S_IN_CH_CTL_16PACK_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if ((channels < 2) ||
+	    (channels > (i2s->max_i2s_chan * 2)) ||
+	    (channels % 2))
+		return -EINVAL;
+
+	control_set |= ((i2s_channels - 1) << IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT);
+
+	ret = img_i2s_in_check_rate(i2s, rate, frame_size,
+			&bclk_filter_enable, &bclk_filter_value);
+	if (ret < 0)
+		return ret;
+
+	if (bclk_filter_enable)
+		chan_control_set |= IMG_I2S_IN_CH_CTL_FEN_MASK;
+
+	if (bclk_filter_value)
+		chan_control_set |= IMG_I2S_IN_CH_CTL_FMODE_MASK;
+
+	control_mask = IMG_I2S_IN_CTL_16PACK_MASK |
+		       IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK;
+
+	chan_control_mask = IMG_I2S_IN_CH_CTL_16PACK_MASK |
+			    IMG_I2S_IN_CH_CTL_FEN_MASK |
+			    IMG_I2S_IN_CH_CTL_FMODE_MASK |
+			    IMG_I2S_IN_CH_CTL_SW_MASK |
+			    IMG_I2S_IN_CH_CTL_FW_MASK |
+			    IMG_I2S_IN_CH_CTL_PACKH_MASK;
+
+	reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
+	reg = (reg & ~control_mask) | control_set;
+	img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL);
+
+	for (i = 0; i < i2s->active_channels; i++)
+		img_i2s_in_ch_disable(i2s, i);
+
+	for (i = 0; i < i2s->max_i2s_chan; i++) {
+		reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
+		reg = (reg & ~chan_control_mask) | chan_control_set;
+		img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+	}
+
+	i2s->active_channels = i2s_channels;
+
+	img_i2s_in_flush(i2s);
+
+	for (i = 0; i < i2s->active_channels; i++)
+		img_i2s_in_ch_enable(i2s, i);
+
+	return 0;
+}
+
+static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
+	int i;
+	u32 chan_control_mask, lrd_set = 0, blkp_set = 0, chan_control_set = 0;
+	u32 reg;
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK;
+		blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		chan_control_set |= IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	chan_control_mask = IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK;
+
+	for (i = 0; i < i2s->active_channels; i++)
+		img_i2s_in_ch_disable(i2s, i);
+
+	/*
+	 * BLKP and LRD must be set during separate register writes
+	 */
+	for (i = 0; i < i2s->max_i2s_chan; i++) {
+		reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
+		reg = (reg & ~chan_control_mask) | chan_control_set;
+		img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+		reg = (reg & ~IMG_I2S_IN_CH_CTL_BLKP_MASK) | blkp_set;
+		img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+		reg = (reg & ~IMG_I2S_IN_CH_CTL_LRD_MASK) | lrd_set;
+		img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+	}
+
+	for (i = 0; i < i2s->active_channels; i++)
+		img_i2s_in_ch_enable(i2s, i);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops img_i2s_in_dai_ops = {
+	.trigger = img_i2s_in_trigger,
+	.hw_params = img_i2s_in_hw_params,
+	.set_fmt = img_i2s_in_set_fmt
+};
+
+static int img_i2s_in_dai_probe(struct snd_soc_dai *dai)
+{
+	struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
+
+	snd_soc_dai_init_dma_data(dai, NULL, &i2s->dma_data);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver img_i2s_in_component = {
+	.name = "img-i2s-in"
+};
+
+static int img_i2s_in_dma_prepare_slave_config(struct snd_pcm_substream *st,
+	struct snd_pcm_hw_params *params, struct dma_slave_config *sc)
+{
+	unsigned int i2s_channels = params_channels(params) / 2;
+	struct snd_soc_pcm_runtime *rtd = st->private_data;
+	struct snd_dmaengine_dai_dma_data *dma_data;
+	int ret;
+
+	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, st);
+
+	ret = snd_hwparams_to_dma_slave_config(st, params, sc);
+	if (ret)
+		return ret;
+
+	sc->src_addr = dma_data->addr;
+	sc->src_addr_width = dma_data->addr_width;
+	sc->src_maxburst = 4 * i2s_channels;
+
+	return 0;
+}
+
+static const struct snd_dmaengine_pcm_config img_i2s_in_dma_config = {
+	.prepare_slave_config = img_i2s_in_dma_prepare_slave_config
+};
+
+static int img_i2s_in_probe(struct platform_device *pdev)
+{
+	struct img_i2s_in *i2s;
+	struct resource *res;
+	void __iomem *base;
+	int ret, i;
+	struct reset_control *rst;
+	unsigned int max_i2s_chan_pow_2;
+	struct device *dev = &pdev->dev;
+
+	i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
+	if (!i2s)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, i2s);
+
+	i2s->dev = dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	i2s->base = base;
+
+	if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels",
+			&i2s->max_i2s_chan)) {
+		dev_err(dev, "No img,i2s-channels property\n");
+		return -EINVAL;
+	}
+
+	max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan);
+
+	i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20);
+
+	i2s->clk_sys = devm_clk_get(dev, "sys");
+	if (IS_ERR(i2s->clk_sys)) {
+		if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER)
+			dev_err(dev, "Failed to acquire clock 'sys'\n");
+		return PTR_ERR(i2s->clk_sys);
+	}
+
+	ret = clk_prepare_enable(i2s->clk_sys);
+	if (ret)
+		return ret;
+
+	i2s->active_channels = 1;
+	i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO;
+	i2s->dma_data.addr_width = 4;
+
+	i2s->dai_driver.probe = img_i2s_in_dai_probe;
+	i2s->dai_driver.capture.channels_min = 2;
+	i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2;
+	i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000;
+	i2s->dai_driver.capture.formats = SNDRV_PCM_FMTBIT_S32_LE |
+		SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE;
+	i2s->dai_driver.ops = &img_i2s_in_dai_ops;
+
+	rst = devm_reset_control_get(dev, "rst");
+	if (IS_ERR(rst)) {
+		if (PTR_ERR(rst) == -EPROBE_DEFER) {
+			ret = -EPROBE_DEFER;
+			goto err_clk_disable;
+		}
+
+		dev_dbg(dev, "No top level reset found\n");
+
+		img_i2s_in_disable(i2s);
+
+		for (i = 0; i < i2s->max_i2s_chan; i++)
+			img_i2s_in_ch_disable(i2s, i);
+	} else {
+		reset_control_assert(rst);
+		reset_control_deassert(rst);
+	}
+
+	img_i2s_in_writel(i2s, 0, IMG_I2S_IN_CTL);
+
+	for (i = 0; i < i2s->max_i2s_chan; i++)
+		img_i2s_in_ch_writel(i2s, i,
+			(4 << IMG_I2S_IN_CH_CTL_CCDEL_SHIFT) |
+			IMG_I2S_IN_CH_CTL_JUST_MASK |
+			IMG_I2S_IN_CH_CTL_FW_MASK, IMG_I2S_IN_CH_CTL);
+
+	ret = devm_snd_soc_register_component(dev, &img_i2s_in_component,
+						&i2s->dai_driver, 1);
+	if (ret)
+		goto err_clk_disable;
+
+	ret = devm_snd_dmaengine_pcm_register(dev, &img_i2s_in_dma_config, 0);
+	if (ret)
+		goto err_clk_disable;
+
+	return 0;
+
+err_clk_disable:
+	clk_disable_unprepare(i2s->clk_sys);
+
+	return ret;
+}
+
+static int img_i2s_in_dev_remove(struct platform_device *pdev)
+{
+	struct img_i2s_in *i2s = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(i2s->clk_sys);
+
+	return 0;
+}
+
+static const struct of_device_id img_i2s_in_of_match[] = {
+	{ .compatible = "img,i2s-in" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, img_i2s_in_of_match);
+
+static struct platform_driver img_i2s_in_driver = {
+	.driver = {
+		.name = "img-i2s-in",
+		.of_match_table = img_i2s_in_of_match
+	},
+	.probe = img_i2s_in_probe,
+	.remove = img_i2s_in_dev_remove
+};
+module_platform_driver(img_i2s_in_driver);
+
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_DESCRIPTION("IMG I2S Input Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c
new file mode 100644
index 0000000..5f99713
--- /dev/null
+++ b/sound/soc/img/img-i2s-out.c
@@ -0,0 +1,565 @@
+/*
+ * IMG I2S output controller driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define IMG_I2S_OUT_TX_FIFO			0x0
+
+#define IMG_I2S_OUT_CTL				0x4
+#define IMG_I2S_OUT_CTL_DATA_EN_MASK		BIT(24)
+#define IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK	0xffe000
+#define IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT	13
+#define IMG_I2S_OUT_CTL_FRM_SIZE_MASK		BIT(8)
+#define IMG_I2S_OUT_CTL_MASTER_MASK		BIT(6)
+#define IMG_I2S_OUT_CTL_CLK_MASK		BIT(5)
+#define IMG_I2S_OUT_CTL_CLK_EN_MASK		BIT(4)
+#define IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK	BIT(3)
+#define IMG_I2S_OUT_CTL_BCLK_POL_MASK		BIT(2)
+#define IMG_I2S_OUT_CTL_ME_MASK			BIT(0)
+
+#define IMG_I2S_OUT_CH_CTL			0x4
+#define IMG_I2S_OUT_CHAN_CTL_CH_MASK		BIT(11)
+#define IMG_I2S_OUT_CHAN_CTL_LT_MASK		BIT(10)
+#define IMG_I2S_OUT_CHAN_CTL_FMT_MASK		0xf0
+#define IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT		4
+#define IMG_I2S_OUT_CHAN_CTL_JUST_MASK		BIT(3)
+#define IMG_I2S_OUT_CHAN_CTL_CLKT_MASK		BIT(1)
+#define IMG_I2S_OUT_CHAN_CTL_ME_MASK		BIT(0)
+
+#define IMG_I2S_OUT_CH_STRIDE			0x20
+
+struct img_i2s_out {
+	void __iomem *base;
+	struct clk *clk_sys;
+	struct clk *clk_ref;
+	struct snd_dmaengine_dai_dma_data dma_data;
+	struct device *dev;
+	unsigned int max_i2s_chan;
+	void __iomem *channel_base;
+	bool force_clk_active;
+	unsigned int active_channels;
+	struct reset_control *rst;
+	struct snd_soc_dai_driver dai_driver;
+};
+
+static int img_i2s_out_suspend(struct device *dev)
+{
+	struct img_i2s_out *i2s = dev_get_drvdata(dev);
+
+	if (!i2s->force_clk_active)
+		clk_disable_unprepare(i2s->clk_ref);
+
+	return 0;
+}
+
+static int img_i2s_out_resume(struct device *dev)
+{
+	struct img_i2s_out *i2s = dev_get_drvdata(dev);
+	int ret;
+
+	if (!i2s->force_clk_active) {
+		ret = clk_prepare_enable(i2s->clk_ref);
+		if (ret) {
+			dev_err(dev, "clk_enable failed: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static inline void img_i2s_out_writel(struct img_i2s_out *i2s, u32 val,
+					u32 reg)
+{
+	writel(val, i2s->base + reg);
+}
+
+static inline u32 img_i2s_out_readl(struct img_i2s_out *i2s, u32 reg)
+{
+	return readl(i2s->base + reg);
+}
+
+static inline void img_i2s_out_ch_writel(struct img_i2s_out *i2s,
+					u32 chan, u32 val, u32 reg)
+{
+	writel(val, i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg);
+}
+
+static inline u32 img_i2s_out_ch_readl(struct img_i2s_out *i2s, u32 chan,
+					u32 reg)
+{
+	return readl(i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg);
+}
+
+static inline void img_i2s_out_ch_disable(struct img_i2s_out *i2s, u32 chan)
+{
+	u32 reg;
+
+	reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL);
+	reg &= ~IMG_I2S_OUT_CHAN_CTL_ME_MASK;
+	img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL);
+}
+
+static inline void img_i2s_out_ch_enable(struct img_i2s_out *i2s, u32 chan)
+{
+	u32 reg;
+
+	reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL);
+	reg |= IMG_I2S_OUT_CHAN_CTL_ME_MASK;
+	img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL);
+}
+
+static inline void img_i2s_out_disable(struct img_i2s_out *i2s)
+{
+	u32 reg;
+
+	reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+	reg &= ~IMG_I2S_OUT_CTL_ME_MASK;
+	img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+}
+
+static inline void img_i2s_out_enable(struct img_i2s_out *i2s)
+{
+	u32 reg;
+
+	reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+	reg |= IMG_I2S_OUT_CTL_ME_MASK;
+	img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+}
+
+static void img_i2s_out_reset(struct img_i2s_out *i2s)
+{
+	int i;
+	u32 core_ctl, chan_ctl;
+
+	core_ctl = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL) &
+			~IMG_I2S_OUT_CTL_ME_MASK &
+			~IMG_I2S_OUT_CTL_DATA_EN_MASK;
+
+	if (!i2s->force_clk_active)
+		core_ctl &= ~IMG_I2S_OUT_CTL_CLK_EN_MASK;
+
+	chan_ctl = img_i2s_out_ch_readl(i2s, 0, IMG_I2S_OUT_CH_CTL) &
+			~IMG_I2S_OUT_CHAN_CTL_ME_MASK;
+
+	reset_control_assert(i2s->rst);
+	reset_control_deassert(i2s->rst);
+
+	for (i = 0; i < i2s->max_i2s_chan; i++)
+		img_i2s_out_ch_writel(i2s, i, chan_ctl, IMG_I2S_OUT_CH_CTL);
+
+	for (i = 0; i < i2s->active_channels; i++)
+		img_i2s_out_ch_enable(i2s, i);
+
+	img_i2s_out_writel(i2s, core_ctl, IMG_I2S_OUT_CTL);
+	img_i2s_out_enable(i2s);
+}
+
+static int img_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd,
+	struct snd_soc_dai *dai)
+{
+	struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
+	u32 reg;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+		if (!i2s->force_clk_active)
+			reg |= IMG_I2S_OUT_CTL_CLK_EN_MASK;
+		reg |= IMG_I2S_OUT_CTL_DATA_EN_MASK;
+		img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		img_i2s_out_reset(i2s);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int img_i2s_out_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
+	unsigned int channels, i2s_channels;
+	long pre_div_a, pre_div_b, diff_a, diff_b, rate, clk_rate;
+	int i;
+	u32 reg, control_mask, control_set = 0;
+	snd_pcm_format_t format;
+
+	rate = params_rate(params);
+	format = params_format(params);
+	channels = params_channels(params);
+	i2s_channels = channels / 2;
+
+	if (format != SNDRV_PCM_FORMAT_S32_LE)
+		return -EINVAL;
+
+	if ((channels < 2) ||
+	    (channels > (i2s->max_i2s_chan * 2)) ||
+	    (channels % 2))
+		return -EINVAL;
+
+	pre_div_a = clk_round_rate(i2s->clk_ref, rate * 256);
+	if (pre_div_a < 0)
+		return pre_div_a;
+	pre_div_b = clk_round_rate(i2s->clk_ref, rate * 384);
+	if (pre_div_b < 0)
+		return pre_div_b;
+
+	diff_a = abs((pre_div_a / 256) - rate);
+	diff_b = abs((pre_div_b / 384) - rate);
+
+	/* If diffs are equal, use lower clock rate */
+	if (diff_a > diff_b)
+		clk_set_rate(i2s->clk_ref, pre_div_b);
+	else
+		clk_set_rate(i2s->clk_ref, pre_div_a);
+
+	/*
+	 * Another driver (eg alsa machine driver) may have rejected the above
+	 * change. Get the current rate and set the register bit according to
+	 * the new minimum diff
+	 */
+	clk_rate = clk_get_rate(i2s->clk_ref);
+
+	diff_a = abs((clk_rate / 256) - rate);
+	diff_b = abs((clk_rate / 384) - rate);
+
+	if (diff_a > diff_b)
+		control_set |= IMG_I2S_OUT_CTL_CLK_MASK;
+
+	control_set |= ((i2s_channels - 1) <<
+		       IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT) &
+		       IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK;
+
+	control_mask = IMG_I2S_OUT_CTL_CLK_MASK |
+		       IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK;
+
+	img_i2s_out_disable(i2s);
+
+	reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+	reg = (reg & ~control_mask) | control_set;
+	img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+
+	for (i = 0; i < i2s_channels; i++)
+		img_i2s_out_ch_enable(i2s, i);
+
+	for (; i < i2s->max_i2s_chan; i++)
+		img_i2s_out_ch_disable(i2s, i);
+
+	img_i2s_out_enable(i2s);
+
+	i2s->active_channels = i2s_channels;
+
+	return 0;
+}
+
+static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
+	int i;
+	bool force_clk_active;
+	u32 chan_control_mask, control_mask, chan_control_set = 0;
+	u32 reg, control_set = 0;
+
+	force_clk_active = ((fmt & SND_SOC_DAIFMT_CLOCK_MASK) ==
+			SND_SOC_DAIFMT_CONT);
+
+	if (force_clk_active)
+		control_set |= IMG_I2S_OUT_CTL_CLK_EN_MASK;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		control_set |= IMG_I2S_OUT_CTL_MASTER_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		control_set |= IMG_I2S_OUT_CTL_BCLK_POL_MASK;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		control_set |= IMG_I2S_OUT_CTL_BCLK_POL_MASK;
+		control_set |= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		control_set |= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		chan_control_set |= IMG_I2S_OUT_CHAN_CTL_CLKT_MASK;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	control_mask = IMG_I2S_OUT_CTL_CLK_EN_MASK |
+		       IMG_I2S_OUT_CTL_MASTER_MASK |
+		       IMG_I2S_OUT_CTL_BCLK_POL_MASK |
+		       IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK;
+
+	chan_control_mask = IMG_I2S_OUT_CHAN_CTL_CLKT_MASK;
+
+	img_i2s_out_disable(i2s);
+
+	reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+	reg = (reg & ~control_mask) | control_set;
+	img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+
+	for (i = 0; i < i2s->active_channels; i++)
+		img_i2s_out_ch_disable(i2s, i);
+
+	for (i = 0; i < i2s->max_i2s_chan; i++) {
+		reg = img_i2s_out_ch_readl(i2s, i, IMG_I2S_OUT_CH_CTL);
+		reg = (reg & ~chan_control_mask) | chan_control_set;
+		img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL);
+	}
+
+	for (i = 0; i < i2s->active_channels; i++)
+		img_i2s_out_ch_enable(i2s, i);
+
+	img_i2s_out_enable(i2s);
+
+	i2s->force_clk_active = force_clk_active;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops img_i2s_out_dai_ops = {
+	.trigger = img_i2s_out_trigger,
+	.hw_params = img_i2s_out_hw_params,
+	.set_fmt = img_i2s_out_set_fmt
+};
+
+static int img_i2s_out_dai_probe(struct snd_soc_dai *dai)
+{
+	struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
+
+	snd_soc_dai_init_dma_data(dai, &i2s->dma_data, NULL);
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver img_i2s_out_component = {
+	.name = "img-i2s-out"
+};
+
+static int img_i2s_out_dma_prepare_slave_config(struct snd_pcm_substream *st,
+	struct snd_pcm_hw_params *params, struct dma_slave_config *sc)
+{
+	unsigned int i2s_channels = params_channels(params) / 2;
+	struct snd_soc_pcm_runtime *rtd = st->private_data;
+	struct snd_dmaengine_dai_dma_data *dma_data;
+	int ret;
+
+	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, st);
+
+	ret = snd_hwparams_to_dma_slave_config(st, params, sc);
+	if (ret)
+		return ret;
+
+	sc->dst_addr = dma_data->addr;
+	sc->dst_addr_width = dma_data->addr_width;
+	sc->dst_maxburst = 4 * i2s_channels;
+
+	return 0;
+}
+
+static const struct snd_dmaengine_pcm_config img_i2s_out_dma_config = {
+	.prepare_slave_config = img_i2s_out_dma_prepare_slave_config
+};
+
+static int img_i2s_out_probe(struct platform_device *pdev)
+{
+	struct img_i2s_out *i2s;
+	struct resource *res;
+	void __iomem *base;
+	int i, ret;
+	unsigned int max_i2s_chan_pow_2;
+	u32 reg;
+	struct device *dev = &pdev->dev;
+
+	i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
+	if (!i2s)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, i2s);
+
+	i2s->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	i2s->base = base;
+
+	if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels",
+			&i2s->max_i2s_chan)) {
+		dev_err(&pdev->dev, "No img,i2s-channels property\n");
+		return -EINVAL;
+	}
+
+	max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan);
+
+	i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20);
+
+	i2s->rst = devm_reset_control_get(&pdev->dev, "rst");
+	if (IS_ERR(i2s->rst)) {
+		if (PTR_ERR(i2s->rst) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "No top level reset found\n");
+		return PTR_ERR(i2s->rst);
+	}
+
+	i2s->clk_sys = devm_clk_get(&pdev->dev, "sys");
+	if (IS_ERR(i2s->clk_sys)) {
+		if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER)
+			dev_err(dev, "Failed to acquire clock 'sys'\n");
+		return PTR_ERR(i2s->clk_sys);
+	}
+
+	i2s->clk_ref = devm_clk_get(&pdev->dev, "ref");
+	if (IS_ERR(i2s->clk_ref)) {
+		if (PTR_ERR(i2s->clk_ref) != -EPROBE_DEFER)
+			dev_err(dev, "Failed to acquire clock 'ref'\n");
+		return PTR_ERR(i2s->clk_ref);
+	}
+
+	ret = clk_prepare_enable(i2s->clk_sys);
+	if (ret)
+		return ret;
+
+	reg = IMG_I2S_OUT_CTL_FRM_SIZE_MASK;
+	img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
+
+	reg = IMG_I2S_OUT_CHAN_CTL_JUST_MASK |
+		IMG_I2S_OUT_CHAN_CTL_LT_MASK |
+		IMG_I2S_OUT_CHAN_CTL_CH_MASK |
+		(8 << IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT);
+
+	for (i = 0; i < i2s->max_i2s_chan; i++)
+		img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL);
+
+	img_i2s_out_reset(i2s);
+
+	pm_runtime_enable(&pdev->dev);
+	if (!pm_runtime_enabled(&pdev->dev)) {
+		ret = img_i2s_out_resume(&pdev->dev);
+		if (ret)
+			goto err_pm_disable;
+	}
+
+	i2s->active_channels = 1;
+	i2s->dma_data.addr = res->start + IMG_I2S_OUT_TX_FIFO;
+	i2s->dma_data.addr_width = 4;
+	i2s->dma_data.maxburst = 4;
+
+	i2s->dai_driver.probe = img_i2s_out_dai_probe;
+	i2s->dai_driver.playback.channels_min = 2;
+	i2s->dai_driver.playback.channels_max = i2s->max_i2s_chan * 2;
+	i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000;
+	i2s->dai_driver.playback.formats = SNDRV_PCM_FMTBIT_S32_LE;
+	i2s->dai_driver.ops = &img_i2s_out_dai_ops;
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+			&img_i2s_out_component, &i2s->dai_driver, 1);
+	if (ret)
+		goto err_suspend;
+
+	ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
+			&img_i2s_out_dma_config, 0);
+	if (ret)
+		goto err_suspend;
+
+	return 0;
+
+err_suspend:
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		img_i2s_out_suspend(&pdev->dev);
+err_pm_disable:
+	pm_runtime_disable(&pdev->dev);
+	clk_disable_unprepare(i2s->clk_sys);
+
+	return ret;
+}
+
+static int img_i2s_out_dev_remove(struct platform_device *pdev)
+{
+	struct img_i2s_out *i2s = platform_get_drvdata(pdev);
+
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		img_i2s_out_suspend(&pdev->dev);
+
+	clk_disable_unprepare(i2s->clk_sys);
+
+	return 0;
+}
+
+static const struct of_device_id img_i2s_out_of_match[] = {
+	{ .compatible = "img,i2s-out" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, img_i2s_out_of_match);
+
+static const struct dev_pm_ops img_i2s_out_pm_ops = {
+	SET_RUNTIME_PM_OPS(img_i2s_out_suspend,
+			   img_i2s_out_resume, NULL)
+};
+
+static struct platform_driver img_i2s_out_driver = {
+	.driver = {
+		.name = "img-i2s-out",
+		.of_match_table = img_i2s_out_of_match,
+		.pm = &img_i2s_out_pm_ops
+	},
+	.probe = img_i2s_out_probe,
+	.remove = img_i2s_out_dev_remove
+};
+module_platform_driver(img_i2s_out_driver);
+
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_DESCRIPTION("IMG I2S Output Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c
new file mode 100644
index 0000000..c1610a0
--- /dev/null
+++ b/sound/soc/img/img-parallel-out.c
@@ -0,0 +1,327 @@
+/*
+ * IMG parallel output controller driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define IMG_PRL_OUT_TX_FIFO		0
+
+#define IMG_PRL_OUT_CTL			0x4
+#define IMG_PRL_OUT_CTL_CH_MASK		BIT(4)
+#define IMG_PRL_OUT_CTL_PACKH_MASK	BIT(3)
+#define IMG_PRL_OUT_CTL_EDGE_MASK	BIT(2)
+#define IMG_PRL_OUT_CTL_ME_MASK		BIT(1)
+#define IMG_PRL_OUT_CTL_SRST_MASK	BIT(0)
+
+struct img_prl_out {
+	void __iomem *base;
+	struct clk *clk_sys;
+	struct clk *clk_ref;
+	struct snd_dmaengine_dai_dma_data dma_data;
+	struct device *dev;
+	struct reset_control *rst;
+};
+
+static int img_prl_out_suspend(struct device *dev)
+{
+	struct img_prl_out *prl = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(prl->clk_ref);
+
+	return 0;
+}
+
+static int img_prl_out_resume(struct device *dev)
+{
+	struct img_prl_out *prl = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(prl->clk_ref);
+	if (ret) {
+		dev_err(dev, "clk_enable failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline void img_prl_out_writel(struct img_prl_out *prl,
+				u32 val, u32 reg)
+{
+	writel(val, prl->base + reg);
+}
+
+static inline u32 img_prl_out_readl(struct img_prl_out *prl, u32 reg)
+{
+	return readl(prl->base + reg);
+}
+
+static void img_prl_out_reset(struct img_prl_out *prl)
+{
+	u32 ctl;
+
+	ctl = img_prl_out_readl(prl, IMG_PRL_OUT_CTL) &
+			~IMG_PRL_OUT_CTL_ME_MASK;
+
+	reset_control_assert(prl->rst);
+	reset_control_deassert(prl->rst);
+
+	img_prl_out_writel(prl, ctl, IMG_PRL_OUT_CTL);
+}
+
+static int img_prl_out_trigger(struct snd_pcm_substream *substream, int cmd,
+			struct snd_soc_dai *dai)
+{
+	struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
+	u32 reg;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL);
+		reg |= IMG_PRL_OUT_CTL_ME_MASK;
+		img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		img_prl_out_reset(prl);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int img_prl_out_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
+	unsigned int rate, channels;
+	u32 reg, control_set = 0;
+	snd_pcm_format_t format;
+
+	rate = params_rate(params);
+	format = params_format(params);
+	channels = params_channels(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S32_LE:
+		control_set |= IMG_PRL_OUT_CTL_PACKH_MASK;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (channels != 2)
+		return -EINVAL;
+
+	clk_set_rate(prl->clk_ref, rate * 256);
+
+	reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL);
+	reg = (reg & ~IMG_PRL_OUT_CTL_PACKH_MASK) | control_set;
+	img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL);
+
+	return 0;
+}
+
+static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
+	u32 reg, control_set = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		control_set |= IMG_PRL_OUT_CTL_EDGE_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL);
+	reg = (reg & ~IMG_PRL_OUT_CTL_EDGE_MASK) | control_set;
+	img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops img_prl_out_dai_ops = {
+	.trigger = img_prl_out_trigger,
+	.hw_params = img_prl_out_hw_params,
+	.set_fmt = img_prl_out_set_fmt
+};
+
+static int img_prl_out_dai_probe(struct snd_soc_dai *dai)
+{
+	struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
+
+	snd_soc_dai_init_dma_data(dai, &prl->dma_data, NULL);
+
+	return 0;
+}
+
+static struct snd_soc_dai_driver img_prl_out_dai = {
+	.probe = img_prl_out_dai_probe,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE
+	},
+	.ops = &img_prl_out_dai_ops
+};
+
+static const struct snd_soc_component_driver img_prl_out_component = {
+	.name = "img-prl-out"
+};
+
+static int img_prl_out_probe(struct platform_device *pdev)
+{
+	struct img_prl_out *prl;
+	struct resource *res;
+	void __iomem *base;
+	int ret;
+	struct device *dev = &pdev->dev;
+
+	prl = devm_kzalloc(&pdev->dev, sizeof(*prl), GFP_KERNEL);
+	if (!prl)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, prl);
+
+	prl->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	prl->base = base;
+
+	prl->rst = devm_reset_control_get(&pdev->dev, "rst");
+	if (IS_ERR(prl->rst)) {
+		if (PTR_ERR(prl->rst) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "No top level reset found\n");
+		return PTR_ERR(prl->rst);
+	}
+
+	prl->clk_sys = devm_clk_get(&pdev->dev, "sys");
+	if (IS_ERR(prl->clk_sys)) {
+		if (PTR_ERR(prl->clk_sys) != -EPROBE_DEFER)
+			dev_err(dev, "Failed to acquire clock 'sys'\n");
+		return PTR_ERR(prl->clk_sys);
+	}
+
+	prl->clk_ref = devm_clk_get(&pdev->dev, "ref");
+	if (IS_ERR(prl->clk_ref)) {
+		if (PTR_ERR(prl->clk_ref) != -EPROBE_DEFER)
+			dev_err(dev, "Failed to acquire clock 'ref'\n");
+		return PTR_ERR(prl->clk_ref);
+	}
+
+	ret = clk_prepare_enable(prl->clk_sys);
+	if (ret)
+		return ret;
+
+	img_prl_out_writel(prl, IMG_PRL_OUT_CTL_EDGE_MASK, IMG_PRL_OUT_CTL);
+	img_prl_out_reset(prl);
+
+	pm_runtime_enable(&pdev->dev);
+	if (!pm_runtime_enabled(&pdev->dev)) {
+		ret = img_prl_out_resume(&pdev->dev);
+		if (ret)
+			goto err_pm_disable;
+	}
+
+	prl->dma_data.addr = res->start + IMG_PRL_OUT_TX_FIFO;
+	prl->dma_data.addr_width = 4;
+	prl->dma_data.maxburst = 4;
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+			&img_prl_out_component,
+			&img_prl_out_dai, 1);
+	if (ret)
+		goto err_suspend;
+
+	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+	if (ret)
+		goto err_suspend;
+
+	return 0;
+
+err_suspend:
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		img_prl_out_suspend(&pdev->dev);
+err_pm_disable:
+	pm_runtime_disable(&pdev->dev);
+	clk_disable_unprepare(prl->clk_sys);
+
+	return ret;
+}
+
+static int img_prl_out_dev_remove(struct platform_device *pdev)
+{
+	struct img_prl_out *prl = platform_get_drvdata(pdev);
+
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		img_prl_out_suspend(&pdev->dev);
+
+	clk_disable_unprepare(prl->clk_sys);
+
+	return 0;
+}
+
+static const struct of_device_id img_prl_out_of_match[] = {
+	{ .compatible = "img,parallel-out" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, img_prl_out_of_match);
+
+static const struct dev_pm_ops img_prl_out_pm_ops = {
+	SET_RUNTIME_PM_OPS(img_prl_out_suspend,
+			   img_prl_out_resume, NULL)
+};
+
+static struct platform_driver img_prl_out_driver = {
+	.driver = {
+		.name = "img-parallel-out",
+		.of_match_table = img_prl_out_of_match,
+		.pm = &img_prl_out_pm_ops
+	},
+	.probe = img_prl_out_probe,
+	.remove = img_prl_out_dev_remove
+};
+module_platform_driver(img_prl_out_driver);
+
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_DESCRIPTION("IMG Parallel Output Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c
new file mode 100644
index 0000000..4d9953d
--- /dev/null
+++ b/sound/soc/img/img-spdif-in.c
@@ -0,0 +1,806 @@
+/*
+ * IMG SPDIF input controller driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define IMG_SPDIF_IN_RX_FIFO_OFFSET		0
+
+#define IMG_SPDIF_IN_CTL			0x4
+#define IMG_SPDIF_IN_CTL_LOCKLO_MASK		0xff
+#define IMG_SPDIF_IN_CTL_LOCKLO_SHIFT		0
+#define IMG_SPDIF_IN_CTL_LOCKHI_MASK		0xff00
+#define IMG_SPDIF_IN_CTL_LOCKHI_SHIFT		8
+#define IMG_SPDIF_IN_CTL_TRK_MASK		0xff0000
+#define IMG_SPDIF_IN_CTL_TRK_SHIFT		16
+#define IMG_SPDIF_IN_CTL_SRD_MASK		0x70000000
+#define IMG_SPDIF_IN_CTL_SRD_SHIFT		28
+#define IMG_SPDIF_IN_CTL_SRT_MASK		BIT(31)
+
+#define IMG_SPDIF_IN_STATUS			0x8
+#define IMG_SPDIF_IN_STATUS_SAM_MASK		0x7000
+#define IMG_SPDIF_IN_STATUS_SAM_SHIFT		12
+#define IMG_SPDIF_IN_STATUS_LOCK_MASK		BIT(15)
+#define IMG_SPDIF_IN_STATUS_LOCK_SHIFT		15
+
+#define IMG_SPDIF_IN_CLKGEN			0x1c
+#define IMG_SPDIF_IN_CLKGEN_NOM_MASK		0x3ff
+#define IMG_SPDIF_IN_CLKGEN_NOM_SHIFT		0
+#define IMG_SPDIF_IN_CLKGEN_HLD_MASK		0x3ff0000
+#define IMG_SPDIF_IN_CLKGEN_HLD_SHIFT		16
+
+#define IMG_SPDIF_IN_CSL			0x20
+
+#define IMG_SPDIF_IN_CSH			0x24
+#define IMG_SPDIF_IN_CSH_MASK			0xff
+#define IMG_SPDIF_IN_CSH_SHIFT			0
+
+#define IMG_SPDIF_IN_SOFT_RESET			0x28
+#define IMG_SPDIF_IN_SOFT_RESET_MASK		BIT(0)
+
+#define IMG_SPDIF_IN_ACLKGEN_START		0x2c
+#define IMG_SPDIF_IN_ACLKGEN_NOM_MASK		0x3ff
+#define IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT		0
+#define IMG_SPDIF_IN_ACLKGEN_HLD_MASK		0xffc00
+#define IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT		10
+#define IMG_SPDIF_IN_ACLKGEN_TRK_MASK		0xff00000
+#define IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT		20
+
+#define IMG_SPDIF_IN_NUM_ACLKGEN		4
+
+struct img_spdif_in {
+	spinlock_t lock;
+	void __iomem *base;
+	struct clk *clk_sys;
+	struct snd_dmaengine_dai_dma_data dma_data;
+	struct device *dev;
+	unsigned int trk;
+	bool multi_freq;
+	int lock_acquire;
+	int lock_release;
+	unsigned int single_freq;
+	unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN];
+	bool active;
+
+	/* Write-only registers */
+	unsigned int aclkgen_regs[IMG_SPDIF_IN_NUM_ACLKGEN];
+};
+
+static inline void img_spdif_in_writel(struct img_spdif_in *spdif,
+					u32 val, u32 reg)
+{
+	writel(val, spdif->base + reg);
+}
+
+static inline u32 img_spdif_in_readl(struct img_spdif_in *spdif, u32 reg)
+{
+	return readl(spdif->base + reg);
+}
+
+static inline void img_spdif_in_aclkgen_writel(struct img_spdif_in *spdif,
+						u32 index)
+{
+	img_spdif_in_writel(spdif, spdif->aclkgen_regs[index],
+			IMG_SPDIF_IN_ACLKGEN_START + (index * 0x4));
+}
+
+static int img_spdif_in_check_max_rate(struct img_spdif_in *spdif,
+		unsigned int sample_rate, unsigned long *actual_freq)
+{
+	unsigned long min_freq, freq_t;
+
+	/* Clock rate must be at least 24x the bit rate */
+	min_freq = sample_rate * 2 * 32 * 24;
+
+	freq_t = clk_get_rate(spdif->clk_sys);
+
+	if (freq_t < min_freq)
+		return -EINVAL;
+
+	*actual_freq = freq_t;
+
+	return 0;
+}
+
+static int img_spdif_in_do_clkgen_calc(unsigned int rate, unsigned int *pnom,
+		unsigned int *phld, unsigned long clk_rate)
+{
+	unsigned int ori, nom, hld;
+
+	/*
+	 * Calculate oversampling ratio, nominal phase increment and hold
+	 * increment for the given rate / frequency
+	 */
+
+	if (!rate)
+		return -EINVAL;
+
+	ori = clk_rate / (rate * 64);
+
+	if (!ori)
+		return -EINVAL;
+
+	nom = (4096 / ori) + 1;
+	do
+		hld = 4096 - (--nom * (ori - 1));
+	while (hld < 120);
+
+	*pnom = nom;
+	*phld = hld;
+
+	return 0;
+}
+
+static int img_spdif_in_do_clkgen_single(struct img_spdif_in *spdif,
+		unsigned int rate)
+{
+	unsigned int nom, hld;
+	unsigned long flags, clk_rate;
+	int ret = 0;
+	u32 reg;
+
+	ret = img_spdif_in_check_max_rate(spdif, rate, &clk_rate);
+	if (ret)
+		return ret;
+
+	ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate);
+	if (ret)
+		return ret;
+
+	reg = (nom << IMG_SPDIF_IN_CLKGEN_NOM_SHIFT) &
+		IMG_SPDIF_IN_CLKGEN_NOM_MASK;
+	reg |= (hld << IMG_SPDIF_IN_CLKGEN_HLD_SHIFT) &
+		IMG_SPDIF_IN_CLKGEN_HLD_MASK;
+
+	spin_lock_irqsave(&spdif->lock, flags);
+
+	if (spdif->active) {
+		spin_unlock_irqrestore(&spdif->lock, flags);
+		return -EBUSY;
+	}
+
+	img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CLKGEN);
+
+	spdif->single_freq = rate;
+
+	spin_unlock_irqrestore(&spdif->lock, flags);
+
+	return 0;
+}
+
+static int img_spdif_in_do_clkgen_multi(struct img_spdif_in *spdif,
+		unsigned int multi_freqs[])
+{
+	unsigned int nom, hld, rate, max_rate = 0;
+	unsigned long flags, clk_rate;
+	int i, ret = 0;
+	u32 reg, trk_reg, temp_regs[IMG_SPDIF_IN_NUM_ACLKGEN];
+
+	for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++)
+		if (multi_freqs[i] > max_rate)
+			max_rate = multi_freqs[i];
+
+	ret = img_spdif_in_check_max_rate(spdif, max_rate, &clk_rate);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) {
+		rate = multi_freqs[i];
+
+		ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate);
+		if (ret)
+			return ret;
+
+		reg = (nom << IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT) &
+			IMG_SPDIF_IN_ACLKGEN_NOM_MASK;
+		reg |= (hld << IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT) &
+			IMG_SPDIF_IN_ACLKGEN_HLD_MASK;
+		temp_regs[i] = reg;
+	}
+
+	spin_lock_irqsave(&spdif->lock, flags);
+
+	if (spdif->active) {
+		spin_unlock_irqrestore(&spdif->lock, flags);
+		return -EBUSY;
+	}
+
+	trk_reg = spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT;
+
+	for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) {
+		spdif->aclkgen_regs[i] = temp_regs[i] | trk_reg;
+		img_spdif_in_aclkgen_writel(spdif, i);
+	}
+
+	spdif->multi_freq = true;
+	spdif->multi_freqs[0] = multi_freqs[0];
+	spdif->multi_freqs[1] = multi_freqs[1];
+	spdif->multi_freqs[2] = multi_freqs[2];
+	spdif->multi_freqs[3] = multi_freqs[3];
+
+	spin_unlock_irqrestore(&spdif->lock, flags);
+
+	return 0;
+}
+
+static int img_spdif_in_iec958_info(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+
+	return 0;
+}
+
+static int img_spdif_in_get_status_mask(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.iec958.status[0] = 0xff;
+	ucontrol->value.iec958.status[1] = 0xff;
+	ucontrol->value.iec958.status[2] = 0xff;
+	ucontrol->value.iec958.status[3] = 0xff;
+	ucontrol->value.iec958.status[4] = 0xff;
+
+	return 0;
+}
+
+static int img_spdif_in_get_status(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+	u32 reg;
+
+	reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSL);
+	ucontrol->value.iec958.status[0] = reg & 0xff;
+	ucontrol->value.iec958.status[1] = (reg >> 8) & 0xff;
+	ucontrol->value.iec958.status[2] = (reg >> 16) & 0xff;
+	ucontrol->value.iec958.status[3] = (reg >> 24) & 0xff;
+	reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSH);
+	ucontrol->value.iec958.status[4] = (reg & IMG_SPDIF_IN_CSH_MASK)
+		>> IMG_SPDIF_IN_CSH_SHIFT;
+
+	return 0;
+}
+
+static int img_spdif_in_info_multi_freq(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = IMG_SPDIF_IN_NUM_ACLKGEN;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = LONG_MAX;
+
+	return 0;
+}
+
+static int img_spdif_in_get_multi_freq(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+	unsigned long flags;
+
+	spin_lock_irqsave(&spdif->lock, flags);
+	if (spdif->multi_freq) {
+		ucontrol->value.integer.value[0] = spdif->multi_freqs[0];
+		ucontrol->value.integer.value[1] = spdif->multi_freqs[1];
+		ucontrol->value.integer.value[2] = spdif->multi_freqs[2];
+		ucontrol->value.integer.value[3] = spdif->multi_freqs[3];
+	} else {
+		ucontrol->value.integer.value[0] = 0;
+		ucontrol->value.integer.value[1] = 0;
+		ucontrol->value.integer.value[2] = 0;
+		ucontrol->value.integer.value[3] = 0;
+	}
+	spin_unlock_irqrestore(&spdif->lock, flags);
+
+	return 0;
+}
+
+static int img_spdif_in_set_multi_freq(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+	unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN];
+	bool multi_freq;
+	unsigned long flags;
+
+	if ((ucontrol->value.integer.value[0] == 0) &&
+			(ucontrol->value.integer.value[1] == 0) &&
+			(ucontrol->value.integer.value[2] == 0) &&
+			(ucontrol->value.integer.value[3] == 0)) {
+		multi_freq = false;
+	} else {
+		multi_freqs[0] = ucontrol->value.integer.value[0];
+		multi_freqs[1] = ucontrol->value.integer.value[1];
+		multi_freqs[2] = ucontrol->value.integer.value[2];
+		multi_freqs[3] = ucontrol->value.integer.value[3];
+		multi_freq = true;
+	}
+
+	if (multi_freq)
+		return img_spdif_in_do_clkgen_multi(spdif, multi_freqs);
+
+	spin_lock_irqsave(&spdif->lock, flags);
+
+	if (spdif->active) {
+		spin_unlock_irqrestore(&spdif->lock, flags);
+		return -EBUSY;
+	}
+
+	spdif->multi_freq = false;
+
+	spin_unlock_irqrestore(&spdif->lock, flags);
+
+	return 0;
+}
+
+static int img_spdif_in_info_lock_freq(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = LONG_MAX;
+
+	return 0;
+}
+
+static int img_spdif_in_get_lock_freq(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *uc)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+	u32 reg;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&spdif->lock, flags);
+
+	reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_STATUS);
+	if (reg & IMG_SPDIF_IN_STATUS_LOCK_MASK) {
+		if (spdif->multi_freq) {
+			i = ((reg & IMG_SPDIF_IN_STATUS_SAM_MASK) >>
+					IMG_SPDIF_IN_STATUS_SAM_SHIFT) - 1;
+			uc->value.integer.value[0] = spdif->multi_freqs[i];
+		} else {
+			uc->value.integer.value[0] = spdif->single_freq;
+		}
+	} else {
+		uc->value.integer.value[0] = 0;
+	}
+
+	spin_unlock_irqrestore(&spdif->lock, flags);
+
+	return 0;
+}
+
+static int img_spdif_in_info_trk(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 255;
+
+	return 0;
+}
+
+static int img_spdif_in_get_trk(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+
+	ucontrol->value.integer.value[0] = spdif->trk;
+
+	return 0;
+}
+
+static int img_spdif_in_set_trk(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+	unsigned long flags;
+	int i;
+	u32 reg;
+
+	spin_lock_irqsave(&spdif->lock, flags);
+
+	if (spdif->active) {
+		spin_unlock_irqrestore(&spdif->lock, flags);
+		return -EBUSY;
+	}
+
+	spdif->trk = ucontrol->value.integer.value[0];
+
+	reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+	reg &= ~IMG_SPDIF_IN_CTL_TRK_MASK;
+	reg |= spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT;
+	img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+
+	for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) {
+		spdif->aclkgen_regs[i] = (spdif->aclkgen_regs[i] &
+			~IMG_SPDIF_IN_ACLKGEN_TRK_MASK) |
+			(spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT);
+
+		img_spdif_in_aclkgen_writel(spdif, i);
+	}
+
+	spin_unlock_irqrestore(&spdif->lock, flags);
+
+	return 0;
+}
+
+static int img_spdif_in_info_lock(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = -128;
+	uinfo->value.integer.max = 127;
+
+	return 0;
+}
+
+static int img_spdif_in_get_lock_acquire(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+
+	ucontrol->value.integer.value[0] = spdif->lock_acquire;
+
+	return 0;
+}
+
+static int img_spdif_in_set_lock_acquire(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&spdif->lock, flags);
+
+	if (spdif->active) {
+		spin_unlock_irqrestore(&spdif->lock, flags);
+		return -EBUSY;
+	}
+
+	spdif->lock_acquire = ucontrol->value.integer.value[0];
+
+	reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+	reg &= ~IMG_SPDIF_IN_CTL_LOCKHI_MASK;
+	reg |= (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) &
+		IMG_SPDIF_IN_CTL_LOCKHI_MASK;
+	img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+
+	spin_unlock_irqrestore(&spdif->lock, flags);
+
+	return 0;
+}
+
+static int img_spdif_in_get_lock_release(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+
+	ucontrol->value.integer.value[0] = spdif->lock_release;
+
+	return 0;
+}
+
+static int img_spdif_in_set_lock_release(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&spdif->lock, flags);
+
+	if (spdif->active) {
+		spin_unlock_irqrestore(&spdif->lock, flags);
+		return -EBUSY;
+	}
+
+	spdif->lock_release = ucontrol->value.integer.value[0];
+
+	reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+	reg &= ~IMG_SPDIF_IN_CTL_LOCKLO_MASK;
+	reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) &
+		IMG_SPDIF_IN_CTL_LOCKLO_MASK;
+	img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+
+	spin_unlock_irqrestore(&spdif->lock, flags);
+
+	return 0;
+}
+
+static struct snd_kcontrol_new img_spdif_in_controls[] = {
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
+		.info = img_spdif_in_iec958_info,
+		.get = img_spdif_in_get_status_mask
+	},
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
+		.info = img_spdif_in_iec958_info,
+		.get = img_spdif_in_get_status
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "SPDIF In Multi Frequency Acquire",
+		.info = img_spdif_in_info_multi_freq,
+		.get = img_spdif_in_get_multi_freq,
+		.put = img_spdif_in_set_multi_freq
+	},
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "SPDIF In Lock Frequency",
+		.info = img_spdif_in_info_lock_freq,
+		.get = img_spdif_in_get_lock_freq
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "SPDIF In Lock TRK",
+		.info = img_spdif_in_info_trk,
+		.get = img_spdif_in_get_trk,
+		.put = img_spdif_in_set_trk
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "SPDIF In Lock Acquire Threshold",
+		.info = img_spdif_in_info_lock,
+		.get = img_spdif_in_get_lock_acquire,
+		.put = img_spdif_in_set_lock_acquire
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "SPDIF In Lock Release Threshold",
+		.info = img_spdif_in_info_lock,
+		.get = img_spdif_in_get_lock_release,
+		.put = img_spdif_in_set_lock_release
+	}
+};
+
+static int img_spdif_in_trigger(struct snd_pcm_substream *substream, int cmd,
+	struct snd_soc_dai *dai)
+{
+	unsigned long flags;
+	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
+	int ret = 0;
+	u32 reg;
+
+	spin_lock_irqsave(&spdif->lock, flags);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+		if (spdif->multi_freq)
+			reg &= ~IMG_SPDIF_IN_CTL_SRD_MASK;
+		else
+			reg |= (1UL << IMG_SPDIF_IN_CTL_SRD_SHIFT);
+		reg |= IMG_SPDIF_IN_CTL_SRT_MASK;
+		img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+		spdif->active = true;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+		reg &= ~IMG_SPDIF_IN_CTL_SRT_MASK;
+		img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+		spdif->active = false;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	spin_unlock_irqrestore(&spdif->lock, flags);
+
+	return ret;
+}
+
+static int img_spdif_in_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
+	unsigned int rate, channels;
+	snd_pcm_format_t format;
+
+	rate = params_rate(params);
+	channels = params_channels(params);
+	format = params_format(params);
+
+	if (format != SNDRV_PCM_FORMAT_S32_LE)
+		return -EINVAL;
+
+	if (channels != 2)
+		return -EINVAL;
+
+	return img_spdif_in_do_clkgen_single(spdif, rate);
+}
+
+static const struct snd_soc_dai_ops img_spdif_in_dai_ops = {
+	.trigger = img_spdif_in_trigger,
+	.hw_params = img_spdif_in_hw_params
+};
+
+static int img_spdif_in_dai_probe(struct snd_soc_dai *dai)
+{
+	struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
+
+	snd_soc_dai_init_dma_data(dai, NULL, &spdif->dma_data);
+
+	snd_soc_add_dai_controls(dai, img_spdif_in_controls,
+			ARRAY_SIZE(img_spdif_in_controls));
+
+	return 0;
+}
+
+static struct snd_soc_dai_driver img_spdif_in_dai = {
+	.probe = img_spdif_in_dai_probe,
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = SNDRV_PCM_FMTBIT_S32_LE
+	},
+	.ops = &img_spdif_in_dai_ops
+};
+
+static const struct snd_soc_component_driver img_spdif_in_component = {
+	.name = "img-spdif-in"
+};
+
+static int img_spdif_in_probe(struct platform_device *pdev)
+{
+	struct img_spdif_in *spdif;
+	struct resource *res;
+	void __iomem *base;
+	int ret;
+	struct reset_control *rst;
+	u32 reg;
+	struct device *dev = &pdev->dev;
+
+	spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL);
+	if (!spdif)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, spdif);
+
+	spdif->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	spdif->base = base;
+
+	spdif->clk_sys = devm_clk_get(dev, "sys");
+	if (IS_ERR(spdif->clk_sys)) {
+		if (PTR_ERR(spdif->clk_sys) != -EPROBE_DEFER)
+			dev_err(dev, "Failed to acquire clock 'sys'\n");
+		return PTR_ERR(spdif->clk_sys);
+	}
+
+	ret = clk_prepare_enable(spdif->clk_sys);
+	if (ret)
+		return ret;
+
+	rst = devm_reset_control_get(&pdev->dev, "rst");
+	if (IS_ERR(rst)) {
+		if (PTR_ERR(rst) == -EPROBE_DEFER) {
+			ret = -EPROBE_DEFER;
+			goto err_clk_disable;
+		}
+		dev_dbg(dev, "No top level reset found\n");
+		img_spdif_in_writel(spdif, IMG_SPDIF_IN_SOFT_RESET_MASK,
+				IMG_SPDIF_IN_SOFT_RESET);
+		img_spdif_in_writel(spdif, 0, IMG_SPDIF_IN_SOFT_RESET);
+	} else {
+		reset_control_assert(rst);
+		reset_control_deassert(rst);
+	}
+
+	spin_lock_init(&spdif->lock);
+
+	spdif->dma_data.addr = res->start + IMG_SPDIF_IN_RX_FIFO_OFFSET;
+	spdif->dma_data.addr_width = 4;
+	spdif->dma_data.maxburst = 4;
+	spdif->trk = 0x80;
+	spdif->lock_acquire = 4;
+	spdif->lock_release = -128;
+
+	reg = (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) &
+		IMG_SPDIF_IN_CTL_LOCKHI_MASK;
+	reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) &
+		IMG_SPDIF_IN_CTL_LOCKLO_MASK;
+	reg |= (spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT) &
+		IMG_SPDIF_IN_CTL_TRK_MASK;
+	img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+			&img_spdif_in_component, &img_spdif_in_dai, 1);
+	if (ret)
+		goto err_clk_disable;
+
+	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+	if (ret)
+		goto err_clk_disable;
+
+	return 0;
+
+err_clk_disable:
+	clk_disable_unprepare(spdif->clk_sys);
+
+	return ret;
+}
+
+static int img_spdif_in_dev_remove(struct platform_device *pdev)
+{
+	struct img_spdif_in *spdif = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(spdif->clk_sys);
+
+	return 0;
+}
+
+static const struct of_device_id img_spdif_in_of_match[] = {
+	{ .compatible = "img,spdif-in" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, img_spdif_in_of_match);
+
+static struct platform_driver img_spdif_in_driver = {
+	.driver = {
+		.name = "img-spdif-in",
+		.of_match_table = img_spdif_in_of_match
+	},
+	.probe = img_spdif_in_probe,
+	.remove = img_spdif_in_dev_remove
+};
+module_platform_driver(img_spdif_in_driver);
+
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_DESCRIPTION("IMG SPDIF Input driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c
new file mode 100644
index 0000000..08f93a5
--- /dev/null
+++ b/sound/soc/img/img-spdif-out.c
@@ -0,0 +1,441 @@
+/*
+ * IMG SPDIF output controller driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define IMG_SPDIF_OUT_TX_FIFO		0x0
+
+#define IMG_SPDIF_OUT_CTL		0x4
+#define IMG_SPDIF_OUT_CTL_FS_MASK	BIT(4)
+#define IMG_SPDIF_OUT_CTL_CLK_MASK	BIT(2)
+#define IMG_SPDIF_OUT_CTL_SRT_MASK	BIT(0)
+
+#define IMG_SPDIF_OUT_CSL		0x14
+
+#define IMG_SPDIF_OUT_CSH_UV		0x18
+#define IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT	0
+#define IMG_SPDIF_OUT_CSH_UV_CSH_MASK	0xff
+
+struct img_spdif_out {
+	spinlock_t lock;
+	void __iomem *base;
+	struct clk *clk_sys;
+	struct clk *clk_ref;
+	struct snd_dmaengine_dai_dma_data dma_data;
+	struct device *dev;
+	struct reset_control *rst;
+};
+
+static int img_spdif_out_suspend(struct device *dev)
+{
+	struct img_spdif_out *spdif = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(spdif->clk_ref);
+
+	return 0;
+}
+
+static int img_spdif_out_resume(struct device *dev)
+{
+	struct img_spdif_out *spdif = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(spdif->clk_ref);
+	if (ret) {
+		dev_err(dev, "clk_enable failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline void img_spdif_out_writel(struct img_spdif_out *spdif, u32 val,
+				u32 reg)
+{
+	writel(val, spdif->base + reg);
+}
+
+static inline u32 img_spdif_out_readl(struct img_spdif_out *spdif, u32 reg)
+{
+	return readl(spdif->base + reg);
+}
+
+static void img_spdif_out_reset(struct img_spdif_out *spdif)
+{
+	u32 ctl, status_low, status_high;
+
+	ctl = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL) &
+			~IMG_SPDIF_OUT_CTL_SRT_MASK;
+	status_low = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSL);
+	status_high = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV);
+
+	reset_control_assert(spdif->rst);
+	reset_control_deassert(spdif->rst);
+
+	img_spdif_out_writel(spdif, ctl, IMG_SPDIF_OUT_CTL);
+	img_spdif_out_writel(spdif, status_low, IMG_SPDIF_OUT_CSL);
+	img_spdif_out_writel(spdif, status_high, IMG_SPDIF_OUT_CSH_UV);
+}
+
+static int img_spdif_out_info(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+
+	return 0;
+}
+
+static int img_spdif_out_get_status_mask(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.iec958.status[0] = 0xff;
+	ucontrol->value.iec958.status[1] = 0xff;
+	ucontrol->value.iec958.status[2] = 0xff;
+	ucontrol->value.iec958.status[3] = 0xff;
+	ucontrol->value.iec958.status[4] = 0xff;
+
+	return 0;
+}
+
+static int img_spdif_out_get_status(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+	u32 reg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&spdif->lock, flags);
+
+	reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSL);
+	ucontrol->value.iec958.status[0] = reg & 0xff;
+	ucontrol->value.iec958.status[1] = (reg >> 8) & 0xff;
+	ucontrol->value.iec958.status[2] = (reg >> 16) & 0xff;
+	ucontrol->value.iec958.status[3] = (reg >> 24) & 0xff;
+
+	reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV);
+	ucontrol->value.iec958.status[4] =
+		(reg & IMG_SPDIF_OUT_CSH_UV_CSH_MASK) >>
+		IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT;
+
+	spin_unlock_irqrestore(&spdif->lock, flags);
+
+	return 0;
+}
+
+static int img_spdif_out_set_status(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(cpu_dai);
+	u32 reg;
+	unsigned long flags;
+
+	reg = ((u32)ucontrol->value.iec958.status[3] << 24);
+	reg |= ((u32)ucontrol->value.iec958.status[2] << 16);
+	reg |= ((u32)ucontrol->value.iec958.status[1] << 8);
+	reg |= (u32)ucontrol->value.iec958.status[0];
+
+	spin_lock_irqsave(&spdif->lock, flags);
+
+	img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CSL);
+
+	reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV);
+	reg &= ~IMG_SPDIF_OUT_CSH_UV_CSH_MASK;
+	reg |= (u32)ucontrol->value.iec958.status[4] <<
+			IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT;
+	img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CSH_UV);
+
+	spin_unlock_irqrestore(&spdif->lock, flags);
+
+	return 0;
+}
+
+static struct snd_kcontrol_new img_spdif_out_controls[] = {
+	{
+		.access = SNDRV_CTL_ELEM_ACCESS_READ,
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
+		.info = img_spdif_out_info,
+		.get = img_spdif_out_get_status_mask
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+		.info = img_spdif_out_info,
+		.get = img_spdif_out_get_status,
+		.put = img_spdif_out_set_status
+	}
+};
+
+static int img_spdif_out_trigger(struct snd_pcm_substream *substream, int cmd,
+			struct snd_soc_dai *dai)
+{
+	struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai);
+	u32 reg;
+	unsigned long flags;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL);
+		reg |= IMG_SPDIF_OUT_CTL_SRT_MASK;
+		img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CTL);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		spin_lock_irqsave(&spdif->lock, flags);
+		img_spdif_out_reset(spdif);
+		spin_unlock_irqrestore(&spdif->lock, flags);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int img_spdif_out_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai);
+	unsigned int channels;
+	long pre_div_a, pre_div_b, diff_a, diff_b, rate, clk_rate;
+	u32 reg;
+	snd_pcm_format_t format;
+
+	rate = params_rate(params);
+	format = params_format(params);
+	channels = params_channels(params);
+
+	dev_dbg(spdif->dev, "hw_params rate %ld channels %u format %u\n",
+			rate, channels, format);
+
+	if (format != SNDRV_PCM_FORMAT_S32_LE)
+		return -EINVAL;
+
+	if (channels != 2)
+		return -EINVAL;
+
+	pre_div_a = clk_round_rate(spdif->clk_ref, rate * 256);
+	if (pre_div_a < 0)
+		return pre_div_a;
+	pre_div_b = clk_round_rate(spdif->clk_ref, rate * 384);
+	if (pre_div_b < 0)
+		return pre_div_b;
+
+	diff_a = abs((pre_div_a / 256) - rate);
+	diff_b = abs((pre_div_b / 384) - rate);
+
+	/* If diffs are equal, use lower clock rate */
+	if (diff_a > diff_b)
+		clk_set_rate(spdif->clk_ref, pre_div_b);
+	else
+		clk_set_rate(spdif->clk_ref, pre_div_a);
+
+	/*
+	 * Another driver (eg machine driver) may have rejected the above
+	 * change. Get the current rate and set the register bit according to
+	 * the new min diff
+	 */
+	clk_rate = clk_get_rate(spdif->clk_ref);
+
+	diff_a = abs((clk_rate / 256) - rate);
+	diff_b = abs((clk_rate / 384) - rate);
+
+	reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL);
+	if (diff_a <= diff_b)
+		reg &= ~IMG_SPDIF_OUT_CTL_CLK_MASK;
+	else
+		reg |= IMG_SPDIF_OUT_CTL_CLK_MASK;
+	img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CTL);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops img_spdif_out_dai_ops = {
+	.trigger = img_spdif_out_trigger,
+	.hw_params = img_spdif_out_hw_params
+};
+
+static int img_spdif_out_dai_probe(struct snd_soc_dai *dai)
+{
+	struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai);
+
+	snd_soc_dai_init_dma_data(dai, &spdif->dma_data, NULL);
+
+	snd_soc_add_dai_controls(dai, img_spdif_out_controls,
+			ARRAY_SIZE(img_spdif_out_controls));
+
+	return 0;
+}
+
+static struct snd_soc_dai_driver img_spdif_out_dai = {
+	.probe = img_spdif_out_dai_probe,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = SNDRV_PCM_FMTBIT_S32_LE
+	},
+	.ops = &img_spdif_out_dai_ops
+};
+
+static const struct snd_soc_component_driver img_spdif_out_component = {
+	.name = "img-spdif-out"
+};
+
+static int img_spdif_out_probe(struct platform_device *pdev)
+{
+	struct img_spdif_out *spdif;
+	struct resource *res;
+	void __iomem *base;
+	int ret;
+	struct device *dev = &pdev->dev;
+
+	spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL);
+	if (!spdif)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, spdif);
+
+	spdif->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	spdif->base = base;
+
+	spdif->rst = devm_reset_control_get(&pdev->dev, "rst");
+	if (IS_ERR(spdif->rst)) {
+		if (PTR_ERR(spdif->rst) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "No top level reset found\n");
+		return PTR_ERR(spdif->rst);
+	}
+
+	spdif->clk_sys = devm_clk_get(&pdev->dev, "sys");
+	if (IS_ERR(spdif->clk_sys)) {
+		if (PTR_ERR(spdif->clk_sys) != -EPROBE_DEFER)
+			dev_err(dev, "Failed to acquire clock 'sys'\n");
+		return PTR_ERR(spdif->clk_sys);
+	}
+
+	spdif->clk_ref = devm_clk_get(&pdev->dev, "ref");
+	if (IS_ERR(spdif->clk_ref)) {
+		if (PTR_ERR(spdif->clk_ref) != -EPROBE_DEFER)
+			dev_err(dev, "Failed to acquire clock 'ref'\n");
+		return PTR_ERR(spdif->clk_ref);
+	}
+
+	ret = clk_prepare_enable(spdif->clk_sys);
+	if (ret)
+		return ret;
+
+	img_spdif_out_writel(spdif, IMG_SPDIF_OUT_CTL_FS_MASK,
+				IMG_SPDIF_OUT_CTL);
+
+	img_spdif_out_reset(spdif);
+
+	pm_runtime_enable(&pdev->dev);
+	if (!pm_runtime_enabled(&pdev->dev)) {
+		ret = img_spdif_out_resume(&pdev->dev);
+		if (ret)
+			goto err_pm_disable;
+	}
+
+	spin_lock_init(&spdif->lock);
+
+	spdif->dma_data.addr = res->start + IMG_SPDIF_OUT_TX_FIFO;
+	spdif->dma_data.addr_width = 4;
+	spdif->dma_data.maxburst = 4;
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+			&img_spdif_out_component,
+			&img_spdif_out_dai, 1);
+	if (ret)
+		goto err_suspend;
+
+	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+	if (ret)
+		goto err_suspend;
+
+	dev_dbg(&pdev->dev, "Probe successful\n");
+
+	return 0;
+
+err_suspend:
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		img_spdif_out_suspend(&pdev->dev);
+err_pm_disable:
+	pm_runtime_disable(&pdev->dev);
+	clk_disable_unprepare(spdif->clk_sys);
+
+	return ret;
+}
+
+static int img_spdif_out_dev_remove(struct platform_device *pdev)
+{
+	struct img_spdif_out *spdif = platform_get_drvdata(pdev);
+
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		img_spdif_out_suspend(&pdev->dev);
+
+	clk_disable_unprepare(spdif->clk_sys);
+
+	return 0;
+}
+
+static const struct of_device_id img_spdif_out_of_match[] = {
+	{ .compatible = "img,spdif-out" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, img_spdif_out_of_match);
+
+static const struct dev_pm_ops img_spdif_out_pm_ops = {
+	SET_RUNTIME_PM_OPS(img_spdif_out_suspend,
+			   img_spdif_out_resume, NULL)
+};
+
+static struct platform_driver img_spdif_out_driver = {
+	.driver = {
+		.name = "img-spdif-out",
+		.of_match_table = img_spdif_out_of_match,
+		.pm = &img_spdif_out_pm_ops
+	},
+	.probe = img_spdif_out_probe,
+	.remove = img_spdif_out_dev_remove
+};
+module_platform_driver(img_spdif_out_driver);
+
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_DESCRIPTION("IMG SPDIF Output driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/img/pistachio-internal-dac.c b/sound/soc/img/pistachio-internal-dac.c
new file mode 100644
index 0000000..162a0fd
--- /dev/null
+++ b/sound/soc/img/pistachio-internal-dac.c
@@ -0,0 +1,287 @@
+/*
+ * Pistachio internal dac driver
+ *
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * Author: Damien Horsley <Damien.Horsley@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define PISTACHIO_INTERNAL_DAC_CTRL			0x40
+#define PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK	0x2
+#define PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK		0x1
+
+#define PISTACHIO_INTERNAL_DAC_SRST			0x44
+#define PISTACHIO_INTERNAL_DAC_SRST_MASK		0x1
+
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL			0x48
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT	0
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK	0xFFF
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK		0x1000
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT	13
+#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK	0x1FE000
+
+#define PISTACHIO_INTERNAL_DAC_PWR			0x1
+#define PISTACHIO_INTERNAL_DAC_PWR_MASK			0x1
+
+#define PISTACHIO_INTERNAL_DAC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE |  \
+					SNDRV_PCM_FMTBIT_S32_LE)
+
+/* codec private data */
+struct pistachio_internal_dac {
+	struct regmap *regmap;
+	struct regulator *supply;
+	bool mute;
+};
+
+static const struct snd_kcontrol_new pistachio_internal_dac_snd_controls[] = {
+	SOC_SINGLE("Playback Switch", PISTACHIO_INTERNAL_DAC_CTRL, 2, 1, 1)
+};
+
+static const struct snd_soc_dapm_widget pistachio_internal_dac_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_OUTPUT("AOUTL"),
+	SND_SOC_DAPM_OUTPUT("AOUTR"),
+};
+
+static const struct snd_soc_dapm_route pistachio_internal_dac_routes[] = {
+	{ "AOUTL", NULL, "DAC" },
+	{ "AOUTR", NULL, "DAC" },
+};
+
+static void pistachio_internal_dac_reg_writel(struct regmap *top_regs,
+						u32 val, u32 reg)
+{
+	regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
+			PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK,
+			reg << PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT);
+
+	regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
+			PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK,
+			val << PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT);
+
+	regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
+			PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK,
+			PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK);
+
+	regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
+			PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK, 0);
+}
+
+static void pistachio_internal_dac_pwr_off(struct pistachio_internal_dac *dac)
+{
+	regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
+		PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK,
+		PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK);
+
+	pistachio_internal_dac_reg_writel(dac->regmap, 0,
+					PISTACHIO_INTERNAL_DAC_PWR);
+}
+
+static void pistachio_internal_dac_pwr_on(struct pistachio_internal_dac *dac)
+{
+	regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST,
+			PISTACHIO_INTERNAL_DAC_SRST_MASK,
+			PISTACHIO_INTERNAL_DAC_SRST_MASK);
+
+	regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST,
+			PISTACHIO_INTERNAL_DAC_SRST_MASK, 0);
+
+	pistachio_internal_dac_reg_writel(dac->regmap,
+					PISTACHIO_INTERNAL_DAC_PWR_MASK,
+					PISTACHIO_INTERNAL_DAC_PWR);
+
+	regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
+			PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK, 0);
+}
+
+static struct snd_soc_dai_driver pistachio_internal_dac_dais[] = {
+	{
+		.name = "pistachio_internal_dac",
+		.playback = {
+			.stream_name = "Playback",
+			.channels_min = 2,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = PISTACHIO_INTERNAL_DAC_FORMATS,
+		}
+	},
+};
+
+static int pistachio_internal_dac_codec_probe(struct snd_soc_codec *codec)
+{
+	struct pistachio_internal_dac *dac = snd_soc_codec_get_drvdata(codec);
+
+	snd_soc_codec_init_regmap(codec, dac->regmap);
+
+	return 0;
+}
+
+static const struct snd_soc_codec_driver pistachio_internal_dac_driver = {
+	.probe = pistachio_internal_dac_codec_probe,
+	.idle_bias_off = true,
+	.controls = pistachio_internal_dac_snd_controls,
+	.num_controls = ARRAY_SIZE(pistachio_internal_dac_snd_controls),
+	.dapm_widgets = pistachio_internal_dac_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(pistachio_internal_dac_widgets),
+	.dapm_routes = pistachio_internal_dac_routes,
+	.num_dapm_routes = ARRAY_SIZE(pistachio_internal_dac_routes),
+};
+
+static int pistachio_internal_dac_probe(struct platform_device *pdev)
+{
+	struct pistachio_internal_dac *dac;
+	int ret, voltage;
+	struct device *dev = &pdev->dev;
+	u32 reg;
+
+	dac = devm_kzalloc(dev, sizeof(*dac), GFP_KERNEL);
+
+	if (!dac)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, dac);
+
+	dac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+							    "img,cr-top");
+	if (IS_ERR(dac->regmap))
+		return PTR_ERR(dac->regmap);
+
+	dac->supply = devm_regulator_get(dev, "VDD");
+	if (IS_ERR(dac->supply)) {
+		ret = PTR_ERR(dac->supply);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "failed to acquire supply 'VDD-supply': %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_enable(dac->supply);
+	if (ret) {
+		dev_err(dev, "failed to enable supply: %d\n", ret);
+		return ret;
+	}
+
+	voltage = regulator_get_voltage(dac->supply);
+
+	switch (voltage) {
+	case 1800000:
+		reg = 0;
+		break;
+	case 3300000:
+		reg = PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK;
+		break;
+	default:
+		dev_err(dev, "invalid voltage: %d\n", voltage);
+		ret = -EINVAL;
+		goto err_regulator;
+	}
+
+	regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
+			PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK, reg);
+
+	pistachio_internal_dac_pwr_off(dac);
+	pistachio_internal_dac_pwr_on(dac);
+
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	pm_runtime_idle(dev);
+
+	ret = snd_soc_register_codec(dev, &pistachio_internal_dac_driver,
+			pistachio_internal_dac_dais,
+			ARRAY_SIZE(pistachio_internal_dac_dais));
+	if (ret) {
+		dev_err(dev, "failed to register codec: %d\n", ret);
+		goto err_pwr;
+	}
+
+	return 0;
+
+err_pwr:
+	pm_runtime_disable(&pdev->dev);
+	pistachio_internal_dac_pwr_off(dac);
+err_regulator:
+	regulator_disable(dac->supply);
+
+	return ret;
+}
+
+static int pistachio_internal_dac_remove(struct platform_device *pdev)
+{
+	struct pistachio_internal_dac *dac = dev_get_drvdata(&pdev->dev);
+
+	snd_soc_unregister_codec(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	pistachio_internal_dac_pwr_off(dac);
+	regulator_disable(dac->supply);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int pistachio_internal_dac_rt_resume(struct device *dev)
+{
+	struct pistachio_internal_dac *dac = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_enable(dac->supply);
+	if (ret) {
+		dev_err(dev, "failed to enable supply: %d\n", ret);
+		return ret;
+	}
+
+	pistachio_internal_dac_pwr_on(dac);
+
+	return 0;
+}
+
+static int pistachio_internal_dac_rt_suspend(struct device *dev)
+{
+	struct pistachio_internal_dac *dac = dev_get_drvdata(dev);
+
+	pistachio_internal_dac_pwr_off(dac);
+
+	regulator_disable(dac->supply);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops pistachio_internal_dac_pm_ops = {
+	SET_RUNTIME_PM_OPS(pistachio_internal_dac_rt_suspend,
+			pistachio_internal_dac_rt_resume, NULL)
+};
+
+static const struct of_device_id pistachio_internal_dac_of_match[] = {
+	{ .compatible = "img,pistachio-internal-dac" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, pistachio_internal_dac_of_match);
+
+static struct platform_driver pistachio_internal_dac_plat_driver = {
+	.driver = {
+		.name = "img-pistachio-internal-dac",
+		.of_match_table = pistachio_internal_dac_of_match,
+		.pm = &pistachio_internal_dac_pm_ops
+	},
+	.probe = pistachio_internal_dac_probe,
+	.remove = pistachio_internal_dac_remove
+};
+module_platform_driver(pistachio_internal_dac_plat_driver);
+
+MODULE_DESCRIPTION("Pistachio Internal DAC driver");
+MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index d430ef5..803f95e 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -24,6 +24,7 @@
 config SND_SST_IPC_ACPI
 	tristate
 	select SND_SST_IPC
+	select SND_SOC_INTEL_SST
 	depends on ACPI
 
 config SND_SOC_INTEL_SST
@@ -43,7 +44,7 @@
 config SND_SOC_INTEL_HASWELL_MACH
 	tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
 	depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
-	depends on DW_DMAC_CORE
+	depends on DW_DMAC_CORE=y
 	select SND_SOC_INTEL_SST
 	select SND_SOC_INTEL_HASWELL
 	select SND_SOC_RT5640
@@ -56,18 +57,19 @@
 config SND_SOC_INTEL_BYT_RT5640_MACH
 	tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
 	depends on X86_INTEL_LPSS && I2C
-	depends on DW_DMAC_CORE
+	depends on DW_DMAC_CORE=y && (SND_SOC_INTEL_BYTCR_RT5640_MACH = n)
 	select SND_SOC_INTEL_SST
 	select SND_SOC_INTEL_BAYTRAIL
 	select SND_SOC_RT5640
 	help
 	  This adds audio driver for Intel Baytrail platform based boards
-	  with the RT5640 audio codec.
+	  with the RT5640 audio codec. This driver is deprecated, use
+	  SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality
 
 config SND_SOC_INTEL_BYT_MAX98090_MACH
 	tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
 	depends on X86_INTEL_LPSS && I2C
-	depends on DW_DMAC_CORE
+	depends on DW_DMAC_CORE=y
 	select SND_SOC_INTEL_SST
 	select SND_SOC_INTEL_BAYTRAIL
 	select SND_SOC_MAX98090
@@ -79,7 +81,7 @@
 	tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
 	depends on X86_INTEL_LPSS && I2C && DW_DMAC && \
 		   I2C_DESIGNWARE_PLATFORM
-	depends on DW_DMAC_CORE
+	depends on DW_DMAC_CORE=y
 	select SND_SOC_INTEL_SST
 	select SND_SOC_INTEL_HASWELL
 	select SND_SOC_RT286
@@ -90,14 +92,26 @@
 	  If unsure select "N".
 
 config SND_SOC_INTEL_BYTCR_RT5640_MACH
-	tristate "ASoC Audio DSP Support for MID BYT Platform"
+        tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec"
 	depends on X86 && I2C
 	select SND_SOC_RT5640
 	select SND_SST_MFLD_PLATFORM
 	select SND_SST_IPC_ACPI
 	help
-	  This adds support for ASoC machine driver for Intel(R) MID Baytrail platform
-          used as alsa device in audio substem in Intel(R) MID devices
+          This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
+          platforms with RT5640 audio codec.
+          Say Y if you have such a device
+          If unsure select "N".
+
+config SND_SOC_INTEL_BYTCR_RT5651_MACH
+        tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec"
+	depends on X86 && I2C
+	select SND_SOC_RT5651
+	select SND_SST_MFLD_PLATFORM
+	select SND_SST_IPC_ACPI
+	help
+          This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
+          platforms with RT5651 audio codec.
           Say Y if you have such a device
           If unsure select "N".
 
@@ -154,3 +168,31 @@
 	   with RT286 I2S audio codec.
 	   Say Y if you have such a device
 	   If unsure select "N".
+
+config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
+	tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode"
+	depends on X86_INTEL_LPSS && I2C
+	select SND_SOC_INTEL_SST
+	select SND_SOC_INTEL_SKYLAKE
+	select SND_SOC_NAU8825
+	select SND_SOC_SSM4567
+	select SND_SOC_DMIC
+	help
+	  This adds support for ASoC Onboard Codec I2S machine driver. This will
+	  create an alsa sound card for NAU88L25 + SSM4567.
+	  Say Y if you have such a device
+	  If unsure select "N".
+
+config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
+	tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode"
+	depends on X86_INTEL_LPSS && I2C
+	select SND_SOC_INTEL_SST
+	select SND_SOC_INTEL_SKYLAKE
+	select SND_SOC_NAU8825
+	select SND_SOC_MAX98357A
+	select SND_SOC_DMIC
+	help
+	  This adds support for ASoC Onboard Codec I2S machine driver. This will
+	  create an alsa sound card for NAU88L25 + MAX98357A.
+	  Say Y if you have such a device
+	  If unsure select "N".
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c
index d55388e..b97e6ad 100644
--- a/sound/soc/intel/atom/sst-atom-controls.c
+++ b/sound/soc/intel/atom/sst-atom-controls.c
@@ -443,7 +443,7 @@
 		break;
 
 	case SST_GAIN_MUTE:
-		ucontrol->value.integer.value[0] = gv->mute ? 1 : 0;
+		ucontrol->value.integer.value[0] = gv->mute ? 0 : 1;
 		break;
 
 	case SST_GAIN_RAMP_DURATION:
@@ -479,7 +479,7 @@
 		break;
 
 	case SST_GAIN_MUTE:
-		gv->mute = !!ucontrol->value.integer.value[0];
+		gv->mute = !ucontrol->value.integer.value[0];
 		dev_dbg(cmpnt->dev, "%s: Mute %d\n", mc->pname, gv->mute);
 		break;
 
@@ -1109,6 +1109,7 @@
 	{"media0_in", NULL, "Compress Playback"},
 	{"media1_in", NULL, "Headset Playback"},
 	{"media2_in", NULL, "pcm0_out"},
+	{"media3_in", NULL, "Deepbuffer Playback"},
 
 	{"media0_out mix 0", "media0_in Switch", "media0_in"},
 	{"media0_out mix 0", "media1_in Switch", "media1_in"},
diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h
index 93de804..e011311 100644
--- a/sound/soc/intel/atom/sst-atom-controls.h
+++ b/sound/soc/intel/atom/sst-atom-controls.h
@@ -28,6 +28,7 @@
 
 enum {
 	MERR_DPCM_AUDIO = 0,
+	MERR_DPCM_DEEP_BUFFER,
 	MERR_DPCM_COMPR,
 };
 
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index 0487cfa..55c33dc7 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -98,6 +98,7 @@
 	{MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA1_IN, SST_TASK_ID_MEDIA, 0},
 	{MERR_DPCM_COMPR, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA0_IN, SST_TASK_ID_MEDIA, 0},
 	{MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0},
+	{MERR_DPCM_DEEP_BUFFER, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA3_IN, SST_TASK_ID_MEDIA, 0},
 };
 
 static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
@@ -500,14 +501,25 @@
 		.channels_min = SST_STEREO,
 		.channels_max = SST_STEREO,
 		.rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
 	},
 	.capture = {
 		.stream_name = "Headset Capture",
 		.channels_min = 1,
 		.channels_max = 2,
 		.rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+},
+{
+	.name = "deepbuffer-cpu-dai",
+	.ops = &sst_media_dai_ops,
+	.playback = {
+		.stream_name = "Deepbuffer Playback",
+		.channels_min = SST_STEREO,
+		.channels_max = SST_STEREO,
+		.rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
 	},
 },
 {
@@ -516,10 +528,6 @@
 	.ops = &sst_compr_dai_ops,
 	.playback = {
 		.stream_name = "Compress Playback",
-		.channels_min = SST_STEREO,
-		.channels_max = SST_STEREO,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 	},
 },
 /* BE CPU  Dais */
@@ -760,15 +768,15 @@
 static int sst_soc_prepare(struct device *dev)
 {
 	struct sst_data *drv = dev_get_drvdata(dev);
-	int i;
+	struct snd_soc_pcm_runtime *rtd;
 
 	/* suspend all pcms first */
 	snd_soc_suspend(drv->soc_card->dev);
 	snd_soc_poweroff(drv->soc_card->dev);
 
 	/* set the SSPs to idle */
-	for (i = 0; i < drv->soc_card->num_rtd; i++) {
-		struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
+	list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) {
+		struct snd_soc_dai *dai = rtd->cpu_dai;
 
 		if (dai->active) {
 			send_ssp_cmd(dai, dai->name, 0);
@@ -782,11 +790,11 @@
 static void sst_soc_complete(struct device *dev)
 {
 	struct sst_data *drv = dev_get_drvdata(dev);
-	int i;
+	struct snd_soc_pcm_runtime *rtd;
 
 	/* restart SSPs */
-	for (i = 0; i < drv->soc_card->num_rtd; i++) {
-		struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
+	list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) {
+		struct snd_soc_dai *dai = rtd->cpu_dai;
 
 		if (dai->active) {
 			sst_handle_vb_timer(dai, true);
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index bb19b58..4fce03f 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -40,18 +40,9 @@
 #include <acpi/acpi_bus.h>
 #include "../sst-mfld-platform.h"
 #include "../../common/sst-dsp.h"
+#include "../../common/sst-acpi.h"
 #include "sst.h"
 
-struct sst_machines {
-	char *codec_id;
-	char board[32];
-	char machine[32];
-	void (*machine_quirk)(void);
-	char firmware[FW_NAME_SIZE];
-	struct sst_platform_info *pdata;
-
-};
-
 /* LPE viewpoint addresses */
 #define SST_BYT_IRAM_PHY_START	0xff2c0000
 #define SST_BYT_IRAM_PHY_END	0xff2d4000
@@ -223,37 +214,16 @@
 	return 0;
 }
 
-static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
-				       void *context, void **ret)
-{
-	*(bool *)context = true;
-	return AE_OK;
-}
-
-static struct sst_machines *sst_acpi_find_machine(
-	struct sst_machines *machines)
-{
-	struct sst_machines *mach;
-	bool found = false;
-
-	for (mach = machines; mach->codec_id; mach++)
-		if (ACPI_SUCCESS(acpi_get_devices(mach->codec_id,
-						  sst_acpi_mach_match,
-						  &found, NULL)) && found)
-			return mach;
-
-	return NULL;
-}
-
 static int sst_acpi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	int ret = 0;
 	struct intel_sst_drv *ctx;
 	const struct acpi_device_id *id;
-	struct sst_machines *mach;
+	struct sst_acpi_mach *mach;
 	struct platform_device *mdev;
 	struct platform_device *plat_dev;
+	struct sst_platform_info *pdata;
 	unsigned int dev_id;
 
 	id = acpi_match_device(dev->driver->acpi_match_table, dev);
@@ -261,12 +231,13 @@
 		return -ENODEV;
 	dev_dbg(dev, "for %s", id->id);
 
-	mach = (struct sst_machines *)id->driver_data;
+	mach = (struct sst_acpi_mach *)id->driver_data;
 	mach = sst_acpi_find_machine(mach);
 	if (mach == NULL) {
 		dev_err(dev, "No matching machine driver found\n");
 		return -ENODEV;
 	}
+	pdata = mach->pdata;
 
 	ret = kstrtouint(id->id, 16, &dev_id);
 	if (ret < 0) {
@@ -276,16 +247,23 @@
 
 	dev_dbg(dev, "ACPI device id: %x\n", dev_id);
 
-	plat_dev = platform_device_register_data(dev, mach->pdata->platform, -1, NULL, 0);
+	plat_dev = platform_device_register_data(dev, pdata->platform, -1,
+						NULL, 0);
 	if (IS_ERR(plat_dev)) {
-		dev_err(dev, "Failed to create machine device: %s\n", mach->pdata->platform);
+		dev_err(dev, "Failed to create machine device: %s\n",
+			pdata->platform);
 		return PTR_ERR(plat_dev);
 	}
 
-	/* Create platform device for sst machine driver */
-	mdev = platform_device_register_data(dev, mach->machine, -1, NULL, 0);
+	/*
+	 * Create platform device for sst machine driver,
+	 * pass machine info as pdata
+	 */
+	mdev = platform_device_register_data(dev, mach->drv_name, -1,
+					(const void *)mach, sizeof(*mach));
 	if (IS_ERR(mdev)) {
-		dev_err(dev, "Failed to create machine device: %s\n", mach->machine);
+		dev_err(dev, "Failed to create machine device: %s\n",
+			mach->drv_name);
 		return PTR_ERR(mdev);
 	}
 
@@ -294,8 +272,8 @@
 		return ret;
 
 	/* Fill sst platform data */
-	ctx->pdata = mach->pdata;
-	strcpy(ctx->firmware_name, mach->firmware);
+	ctx->pdata = pdata;
+	strcpy(ctx->firmware_name, mach->fw_filename);
 
 	ret = sst_platform_get_resources(ctx);
 	if (ret)
@@ -342,22 +320,28 @@
 	return 0;
 }
 
-static struct sst_machines sst_acpi_bytcr[] = {
-	{"10EC5640", "T100", "bytt100_rt5640", NULL, "intel/fw_sst_0f28.bin",
+static struct sst_acpi_mach sst_acpi_bytcr[] = {
+	{"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
+						&byt_rvp_platform_data },
+	{"10EC5642", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
+						&byt_rvp_platform_data },
+	{"INTCCFFD", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
+						&byt_rvp_platform_data },
+	{"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL,
 						&byt_rvp_platform_data },
 	{},
 };
 
 /* Cherryview-based platforms: CherryTrail and Braswell */
-static struct sst_machines sst_acpi_chv[] = {
-	{"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "intel/fw_sst_22a8.bin",
+static struct sst_acpi_mach sst_acpi_chv[] = {
+	{"10EC5670", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
 						&chv_platform_data },
-	{"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin",
+	{"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
 						&chv_platform_data },
-	{"10EC5650", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin",
+	{"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
 						&chv_platform_data },
-	{"193C9890", "cht-bsw", "cht-bsw-max98090", NULL,
-	"intel/fw_sst_22a8.bin", &chv_platform_data },
+	{"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
+						&chv_platform_data },
 	{},
 };
 
diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c
index a74c64c..4ccc80e 100644
--- a/sound/soc/intel/atom/sst/sst_stream.c
+++ b/sound/soc/intel/atom/sst/sst_stream.c
@@ -108,7 +108,7 @@
 			str_id, pipe_id);
 	ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD,
 			IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param),
-			&alloc_param, data, true, true, false, true);
+			&alloc_param, &data, true, true, false, true);
 
 	if (ret < 0) {
 		dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c
index 79547be..4765ad4 100644
--- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c
+++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c
@@ -377,6 +377,8 @@
 
 	priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data),
 				 GFP_KERNEL);
+	if (!priv_data)
+		return -ENOMEM;
 	priv_data->byt = plat_data->dsp;
 	snd_soc_platform_set_drvdata(platform, priv_data);
 
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 371c456..3310c0f 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -3,17 +3,23 @@
 snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
 snd-soc-sst-broadwell-objs := broadwell.o
 snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o
+snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o
 snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
 snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
 snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o
 snd-soc-skl_rt286-objs := skl_rt286.o
+snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
+snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o
 
 obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
 obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
 obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
 obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
 obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o
+obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o
 obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
+obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o
+obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 7a5c9a3..9a1752d 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -20,51 +20,76 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/acpi.h>
 #include <linux/device.h>
+#include <linux/dmi.h>
 #include <linux/slab.h>
-#include <linux/input.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/jack.h>
 #include "../../codecs/rt5640.h"
 #include "../atom/sst-atom-controls.h"
+#include "../common/sst-acpi.h"
 
-static const struct snd_soc_dapm_widget byt_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
 	SND_SOC_DAPM_HP("Headphone", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
-	SND_SOC_DAPM_MIC("Int Mic", NULL),
-	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+	SND_SOC_DAPM_MIC("Internal Mic", NULL),
+	SND_SOC_DAPM_SPK("Speaker", NULL),
 };
 
-static const struct snd_soc_dapm_route byt_audio_map[] = {
-	{"IN2P", NULL, "Headset Mic"},
-	{"IN2N", NULL, "Headset Mic"},
-	{"Headset Mic", NULL, "MICBIAS1"},
-	{"IN1P", NULL, "MICBIAS1"},
-	{"LDO2", NULL, "Int Mic"},
-	{"Headphone", NULL, "HPOL"},
-	{"Headphone", NULL, "HPOR"},
-	{"Ext Spk", NULL, "SPOLP"},
-	{"Ext Spk", NULL, "SPOLN"},
-	{"Ext Spk", NULL, "SPORP"},
-	{"Ext Spk", NULL, "SPORN"},
-
+static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
 	{"AIF1 Playback", NULL, "ssp2 Tx"},
 	{"ssp2 Tx", NULL, "codec_out0"},
 	{"ssp2 Tx", NULL, "codec_out1"},
 	{"codec_in0", NULL, "ssp2 Rx"},
 	{"codec_in1", NULL, "ssp2 Rx"},
 	{"ssp2 Rx", NULL, "AIF1 Capture"},
+
+	{"Headset Mic", NULL, "MICBIAS1"},
+	{"IN2P", NULL, "Headset Mic"},
+	{"Headphone", NULL, "HPOL"},
+	{"Headphone", NULL, "HPOR"},
+	{"Speaker", NULL, "SPOLP"},
+	{"Speaker", NULL, "SPOLN"},
+	{"Speaker", NULL, "SPORP"},
+	{"Speaker", NULL, "SPORN"},
 };
 
-static const struct snd_kcontrol_new byt_mc_controls[] = {
+static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = {
+	{"DMIC1", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = {
+	{"DMIC2", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
+	{"Internal Mic", NULL, "MICBIAS1"},
+	{"IN1P", NULL, "Internal Mic"},
+};
+
+enum {
+	BYT_RT5640_DMIC1_MAP,
+	BYT_RT5640_DMIC2_MAP,
+	BYT_RT5640_IN1_MAP,
+};
+
+#define BYT_RT5640_MAP(quirk)	((quirk) & 0xff)
+#define BYT_RT5640_DMIC_EN	BIT(16)
+
+static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
+					BYT_RT5640_DMIC_EN;
+
+static const struct snd_kcontrol_new byt_rt5640_controls[] = {
 	SOC_DAPM_PIN_SWITCH("Headphone"),
 	SOC_DAPM_PIN_SWITCH("Headset Mic"),
-	SOC_DAPM_PIN_SWITCH("Int Mic"),
-	SOC_DAPM_PIN_SWITCH("Ext Spk"),
+	SOC_DAPM_PIN_SWITCH("Internal Mic"),
+	SOC_DAPM_PIN_SWITCH("Speaker"),
 };
 
-static int byt_aif1_hw_params(struct snd_pcm_substream *substream,
+static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream,
 					struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -92,7 +117,95 @@
 	return 0;
 }
 
-static const struct snd_soc_pcm_stream byt_dai_params = {
+static int byt_rt5640_quirk_cb(const struct dmi_system_id *id)
+{
+	byt_rt5640_quirk = (unsigned long)id->driver_data;
+	return 1;
+}
+
+static const struct dmi_system_id byt_rt5640_quirk_table[] = {
+	{
+		.callback = byt_rt5640_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+		},
+		.driver_data = (unsigned long *)BYT_RT5640_IN1_MAP,
+	},
+	{
+		.callback = byt_rt5640_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "DellInc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
+		},
+		.driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP |
+						 BYT_RT5640_DMIC_EN),
+	},
+	{
+		.callback = byt_rt5640_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"),
+		},
+		.driver_data = (unsigned long *)BYT_RT5640_IN1_MAP,
+	},
+	{}
+};
+
+static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
+{
+	int ret;
+	struct snd_soc_codec *codec = runtime->codec;
+	struct snd_soc_card *card = runtime->card;
+	const struct snd_soc_dapm_route *custom_map;
+	int num_routes;
+
+	card->dapm.idle_bias_off = true;
+
+	rt5640_sel_asrc_clk_src(codec,
+				RT5640_DA_STEREO_FILTER |
+				RT5640_AD_STEREO_FILTER,
+				RT5640_CLK_SEL_ASRC);
+
+	ret = snd_soc_add_card_controls(card, byt_rt5640_controls,
+					ARRAY_SIZE(byt_rt5640_controls));
+	if (ret) {
+		dev_err(card->dev, "unable to add card controls\n");
+		return ret;
+	}
+
+	dmi_check_system(byt_rt5640_quirk_table);
+	switch (BYT_RT5640_MAP(byt_rt5640_quirk)) {
+	case BYT_RT5640_IN1_MAP:
+		custom_map = byt_rt5640_intmic_in1_map;
+		num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map);
+		break;
+	case BYT_RT5640_DMIC2_MAP:
+		custom_map = byt_rt5640_intmic_dmic2_map;
+		num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map);
+		break;
+	default:
+		custom_map = byt_rt5640_intmic_dmic1_map;
+		num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
+	}
+
+	ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
+	if (ret)
+		return ret;
+
+	if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
+		ret = rt5640_dmic_enable(codec, 0, 0);
+		if (ret)
+			return ret;
+	}
+
+	snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
+	snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
+
+	return ret;
+}
+
+static const struct snd_soc_pcm_stream byt_rt5640_dai_params = {
 	.formats = SNDRV_PCM_FMTBIT_S24_LE,
 	.rate_min = 48000,
 	.rate_max = 48000,
@@ -100,13 +213,14 @@
 	.channels_max = 2,
 };
 
-static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd,
+static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd,
 			    struct snd_pcm_hw_params *params)
 {
 	struct snd_interval *rate = hw_param_interval(params,
 			SNDRV_PCM_HW_PARAM_RATE);
 	struct snd_interval *channels = hw_param_interval(params,
 						SNDRV_PCM_HW_PARAM_CHANNELS);
+	int ret;
 
 	/* The DSP will covert the FE rate to 48k, stereo, 24bits */
 	rate->min = rate->max = 48000;
@@ -114,24 +228,46 @@
 
 	/* set SSP2 to 24-bit */
 	params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+
+	/*
+	 * Default mode for SSP configuration is TDM 4 slot, override config
+	 * with explicit setting to I2S 2ch 24-bit. The word length is set with
+	 * dai_set_tdm_slot() since there is no other API exposed
+	 */
+	ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
+				  SND_SOC_DAIFMT_I2S     |
+				  SND_SOC_DAIFMT_NB_IF   |
+				  SND_SOC_DAIFMT_CBS_CFS
+				  );
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
+		return ret;
+	}
+
 	return 0;
 }
 
-static int byt_aif1_startup(struct snd_pcm_substream *substream)
+static int byt_rt5640_aif1_startup(struct snd_pcm_substream *substream)
 {
 	return snd_pcm_hw_constraint_single(substream->runtime,
 			SNDRV_PCM_HW_PARAM_RATE, 48000);
 }
 
-static struct snd_soc_ops byt_aif1_ops = {
-	.startup = byt_aif1_startup,
+static struct snd_soc_ops byt_rt5640_aif1_ops = {
+	.startup = byt_rt5640_aif1_startup,
 };
 
-static struct snd_soc_ops byt_be_ssp2_ops = {
-	.hw_params = byt_aif1_hw_params,
+static struct snd_soc_ops byt_rt5640_be_ssp2_ops = {
+	.hw_params = byt_rt5640_aif1_hw_params,
 };
 
-static struct snd_soc_dai_link byt_dailink[] = {
+static struct snd_soc_dai_link byt_rt5640_dais[] = {
 	[MERR_DPCM_AUDIO] = {
 		.name = "Baytrail Audio Port",
 		.stream_name = "Baytrail Audio",
@@ -143,7 +279,20 @@
 		.dynamic = 1,
 		.dpcm_playback = 1,
 		.dpcm_capture = 1,
-		.ops = &byt_aif1_ops,
+		.ops = &byt_rt5640_aif1_ops,
+	},
+	[MERR_DPCM_DEEP_BUFFER] = {
+		.name = "Deep-Buffer Audio Port",
+		.stream_name = "Deep-Buffer Audio",
+		.cpu_dai_name = "deepbuffer-cpu-dai",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.platform_name = "sst-mfld-platform",
+		.ignore_suspend = 1,
+		.nonatomic = true,
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.ops = &byt_rt5640_aif1_ops,
 	},
 	[MERR_DPCM_COMPR] = {
 		.name = "Baytrail Compressed Port",
@@ -161,58 +310,69 @@
 		.platform_name = "sst-mfld-platform",
 		.no_pcm = 1,
 		.codec_dai_name = "rt5640-aif1",
-		.codec_name = "i2c-10EC5640:00",
+		.codec_name = "i2c-10EC5640:00", /* overwritten with HID */
 		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 						| SND_SOC_DAIFMT_CBS_CFS,
-		.be_hw_params_fixup = byt_codec_fixup,
+		.be_hw_params_fixup = byt_rt5640_codec_fixup,
 		.ignore_suspend = 1,
 		.dpcm_playback = 1,
 		.dpcm_capture = 1,
-		.ops = &byt_be_ssp2_ops,
+		.init = byt_rt5640_init,
+		.ops = &byt_rt5640_be_ssp2_ops,
 	},
 };
 
 /* SoC card */
-static struct snd_soc_card snd_soc_card_byt = {
-	.name = "baytrailcraudio",
+static struct snd_soc_card byt_rt5640_card = {
+	.name = "bytcr-rt5640",
 	.owner = THIS_MODULE,
-	.dai_link = byt_dailink,
-	.num_links = ARRAY_SIZE(byt_dailink),
-	.dapm_widgets = byt_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(byt_dapm_widgets),
-	.dapm_routes = byt_audio_map,
-	.num_dapm_routes = ARRAY_SIZE(byt_audio_map),
-	.controls = byt_mc_controls,
-	.num_controls = ARRAY_SIZE(byt_mc_controls),
+	.dai_link = byt_rt5640_dais,
+	.num_links = ARRAY_SIZE(byt_rt5640_dais),
+	.dapm_widgets = byt_rt5640_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets),
+	.dapm_routes = byt_rt5640_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
+	.fully_routed = true,
 };
 
-static int snd_byt_mc_probe(struct platform_device *pdev)
+static char byt_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
+
+static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 {
 	int ret_val = 0;
+	struct sst_acpi_mach *mach;
 
 	/* register the soc card */
-	snd_soc_card_byt.dev = &pdev->dev;
+	byt_rt5640_card.dev = &pdev->dev;
+	mach = byt_rt5640_card.dev->platform_data;
 
-	ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_byt);
+	/* fixup codec name based on HID */
+	snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name),
+		 "%s%s%s", "i2c-", mach->id, ":00");
+	byt_rt5640_dais[MERR_DPCM_COMPR+1].codec_name = byt_rt5640_codec_name;
+
+	ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);
+
 	if (ret_val) {
-		dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", ret_val);
+		dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n",
+			ret_val);
 		return ret_val;
 	}
-	platform_set_drvdata(pdev, &snd_soc_card_byt);
+	platform_set_drvdata(pdev, &byt_rt5640_card);
 	return ret_val;
 }
 
-static struct platform_driver snd_byt_mc_driver = {
+static struct platform_driver snd_byt_rt5640_mc_driver = {
 	.driver = {
-		.name = "bytt100_rt5640",
+		.name = "bytcr_rt5640",
 		.pm = &snd_soc_pm_ops,
 	},
-	.probe = snd_byt_mc_probe,
+	.probe = snd_byt_rt5640_mc_probe,
 };
 
-module_platform_driver(snd_byt_mc_driver);
+module_platform_driver(snd_byt_rt5640_mc_driver);
 
 MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
 MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>");
 MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:bytt100_rt5640");
+MODULE_ALIAS("platform:bytcr_rt5640");
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
new file mode 100644
index 0000000..1c95ccc
--- /dev/null
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -0,0 +1,332 @@
+/*
+ *  bytcr_rt5651.c - ASoc Machine driver for Intel Byt CR platform
+ *  (derived from bytcr_rt5640.c)
+ *
+ *  Copyright (C) 2015 Intel Corp
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../../codecs/rt5651.h"
+#include "../atom/sst-atom-controls.h"
+
+static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Internal Mic", NULL),
+	SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
+	{"AIF1 Playback", NULL, "ssp2 Tx"},
+	{"ssp2 Tx", NULL, "codec_out0"},
+	{"ssp2 Tx", NULL, "codec_out1"},
+	{"codec_in0", NULL, "ssp2 Rx"},
+	{"codec_in1", NULL, "ssp2 Rx"},
+	{"ssp2 Rx", NULL, "AIF1 Capture"},
+
+	{"Headset Mic", NULL, "micbias1"}, /* lowercase for rt5651 */
+	{"IN2P", NULL, "Headset Mic"},
+	{"Headphone", NULL, "HPOL"},
+	{"Headphone", NULL, "HPOR"},
+	{"Speaker", NULL, "LOUTL"},
+	{"Speaker", NULL, "LOUTR"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic1_map[] = {
+	{"DMIC1", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic2_map[] = {
+	{"DMIC2", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_map[] = {
+	{"Internal Mic", NULL, "micbias1"},
+	{"IN1P", NULL, "Internal Mic"},
+};
+
+enum {
+	BYT_RT5651_DMIC1_MAP,
+	BYT_RT5651_DMIC2_MAP,
+	BYT_RT5651_IN1_MAP,
+};
+
+#define BYT_RT5651_MAP(quirk)	((quirk) & 0xff)
+#define BYT_RT5651_DMIC_EN	BIT(16)
+
+static unsigned long byt_rt5651_quirk = BYT_RT5651_DMIC1_MAP |
+					BYT_RT5651_DMIC_EN;
+
+static const struct snd_kcontrol_new byt_rt5651_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+	SOC_DAPM_PIN_SWITCH("Internal Mic"),
+	SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int ret;
+
+	snd_soc_dai_set_bclk_ratio(codec_dai, 50);
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, RT5651_SCLK_S_PLL1,
+				     params_rate(params) * 512,
+				     SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set codec clock %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_pll(codec_dai, 0, RT5651_PLL1_S_BCLK1,
+				  params_rate(params) * 50,
+				  params_rate(params) * 512);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct dmi_system_id byt_rt5651_quirk_table[] = {
+	{}
+};
+
+static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
+{
+	int ret;
+	struct snd_soc_card *card = runtime->card;
+	const struct snd_soc_dapm_route *custom_map;
+	int num_routes;
+
+	card->dapm.idle_bias_off = true;
+
+	dmi_check_system(byt_rt5651_quirk_table);
+	switch (BYT_RT5651_MAP(byt_rt5651_quirk)) {
+	case BYT_RT5651_IN1_MAP:
+		custom_map = byt_rt5651_intmic_in1_map;
+		num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_map);
+		break;
+	case BYT_RT5651_DMIC2_MAP:
+		custom_map = byt_rt5651_intmic_dmic2_map;
+		num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic2_map);
+		break;
+	default:
+		custom_map = byt_rt5651_intmic_dmic1_map;
+		num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic1_map);
+	}
+
+	ret = snd_soc_add_card_controls(card, byt_rt5651_controls,
+					ARRAY_SIZE(byt_rt5651_controls));
+	if (ret) {
+		dev_err(card->dev, "unable to add card controls\n");
+		return ret;
+	}
+	snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
+	snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
+
+	return ret;
+}
+
+static const struct snd_soc_pcm_stream byt_rt5651_dai_params = {
+	.formats = SNDRV_PCM_FMTBIT_S24_LE,
+	.rate_min = 48000,
+	.rate_max = 48000,
+	.channels_min = 2,
+	.channels_max = 2,
+};
+
+static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd,
+			    struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+						SNDRV_PCM_HW_PARAM_CHANNELS);
+	int ret;
+
+	/* The DSP will covert the FE rate to 48k, stereo, 24bits */
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	/* set SSP2 to 24-bit */
+	params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+
+	/*
+	 * Default mode for SSP configuration is TDM 4 slot, override config
+	 * with explicit setting to I2S 2ch 24-bit. The word length is set with
+	 * dai_set_tdm_slot() since there is no other API exposed
+	 */
+	ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
+				  SND_SOC_DAIFMT_I2S     |
+				  SND_SOC_DAIFMT_NB_IF   |
+				  SND_SOC_DAIFMT_CBS_CFS
+				  );
+
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static unsigned int rates_48000[] = {
+	48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_48000 = {
+	.count = ARRAY_SIZE(rates_48000),
+	.list  = rates_48000,
+};
+
+static int byt_rt5651_aif1_startup(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE,
+			&constraints_48000);
+}
+
+static struct snd_soc_ops byt_rt5651_aif1_ops = {
+	.startup = byt_rt5651_aif1_startup,
+};
+
+static struct snd_soc_ops byt_rt5651_be_ssp2_ops = {
+	.hw_params = byt_rt5651_aif1_hw_params,
+};
+
+static struct snd_soc_dai_link byt_rt5651_dais[] = {
+	[MERR_DPCM_AUDIO] = {
+		.name = "Audio Port",
+		.stream_name = "Audio",
+		.cpu_dai_name = "media-cpu-dai",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.platform_name = "sst-mfld-platform",
+		.ignore_suspend = 1,
+		.nonatomic = true,
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.ops = &byt_rt5651_aif1_ops,
+	},
+	[MERR_DPCM_DEEP_BUFFER] = {
+		.name = "Deep-Buffer Audio Port",
+		.stream_name = "Deep-Buffer Audio",
+		.cpu_dai_name = "deepbuffer-cpu-dai",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.platform_name = "sst-mfld-platform",
+		.ignore_suspend = 1,
+		.nonatomic = true,
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.ops = &byt_rt5651_aif1_ops,
+	},
+	[MERR_DPCM_COMPR] = {
+		.name = "Compressed Port",
+		.stream_name = "Compress",
+		.cpu_dai_name = "compress-cpu-dai",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.platform_name = "sst-mfld-platform",
+	},
+	/* CODEC<->CODEC link */
+	/* back ends */
+	{
+		.name = "SSP2-Codec",
+		.be_id = 1,
+		.cpu_dai_name = "ssp2-port",
+		.platform_name = "sst-mfld-platform",
+		.no_pcm = 1,
+		.codec_dai_name = "rt5651-aif1",
+		.codec_name = "i2c-10EC5651:00",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+						| SND_SOC_DAIFMT_CBS_CFS,
+		.be_hw_params_fixup = byt_rt5651_codec_fixup,
+		.ignore_suspend = 1,
+		.nonatomic = true,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.init = byt_rt5651_init,
+		.ops = &byt_rt5651_be_ssp2_ops,
+	},
+};
+
+/* SoC card */
+static struct snd_soc_card byt_rt5651_card = {
+	.name = "bytcr-rt5651",
+	.owner = THIS_MODULE,
+	.dai_link = byt_rt5651_dais,
+	.num_links = ARRAY_SIZE(byt_rt5651_dais),
+	.dapm_widgets = byt_rt5651_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(byt_rt5651_widgets),
+	.dapm_routes = byt_rt5651_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(byt_rt5651_audio_map),
+	.fully_routed = true,
+};
+
+static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
+{
+	int ret_val = 0;
+
+	/* register the soc card */
+	byt_rt5651_card.dev = &pdev->dev;
+
+	ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card);
+
+	if (ret_val) {
+		dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n",
+			ret_val);
+		return ret_val;
+	}
+	platform_set_drvdata(pdev, &byt_rt5651_card);
+	return ret_val;
+}
+
+static struct platform_driver snd_byt_rt5651_mc_driver = {
+	.driver = {
+		.name = "bytcr_rt5651",
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe = snd_byt_rt5651_mc_probe,
+};
+
+module_platform_driver(snd_byt_rt5651_mc_driver);
+
+MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver for RT5651");
+MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bytcr_rt5651");
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
index 4e2fcf1..90588d6 100644
--- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c
+++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
@@ -41,12 +41,9 @@
 
 static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
 {
-	int i;
+	struct snd_soc_pcm_runtime *rtd;
 
-	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_pcm_runtime *rtd;
-
-		rtd = card->rtd + i;
+	list_for_each_entry(rtd, &card->rtd_list, list) {
 		if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
 			     strlen(CHT_CODEC_DAI)))
 			return rtd->codec_dai;
@@ -235,6 +232,18 @@
 		.dpcm_capture = 1,
 		.ops = &cht_aif1_ops,
 	},
+	[MERR_DPCM_DEEP_BUFFER] = {
+		.name = "Deep-Buffer Audio Port",
+		.stream_name = "Deep-Buffer Audio",
+		.cpu_dai_name = "deepbuffer-cpu-dai",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.platform_name = "sst-mfld-platform",
+		.nonatomic = true,
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.ops = &cht_aif1_ops,
+	},
 	[MERR_DPCM_COMPR] = {
 		.name = "Compressed Port",
 		.stream_name = "Compress",
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index 38d65a3..2d3afdd 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -47,12 +47,9 @@
 
 static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
 {
-	int i;
+	struct snd_soc_pcm_runtime *rtd;
 
-	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_pcm_runtime *rtd;
-
-		rtd = card->rtd + i;
+	list_for_each_entry(rtd, &card->rtd_list, list) {
 		if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
 			     strlen(CHT_CODEC_DAI)))
 			return rtd->codec_dai;
@@ -263,6 +260,18 @@
 		.dpcm_capture = 1,
 		.ops = &cht_aif1_ops,
 	},
+	[MERR_DPCM_DEEP_BUFFER] = {
+		.name = "Deep-Buffer Audio Port",
+		.stream_name = "Deep-Buffer Audio",
+		.cpu_dai_name = "deepbuffer-cpu-dai",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.platform_name = "sst-mfld-platform",
+		.nonatomic = true,
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.ops = &cht_aif1_ops,
+	},
 	[MERR_DPCM_COMPR] = {
 		.name = "Compressed Port",
 		.stream_name = "Compress",
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index 5621ccd..2e5347f 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -46,12 +46,9 @@
 
 static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
 {
-	int i;
+	struct snd_soc_pcm_runtime *rtd;
 
-	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_pcm_runtime *rtd;
-
-		rtd = card->rtd + i;
+	list_for_each_entry(rtd, &card->rtd_list, list) {
 		if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
 			     strlen(CHT_CODEC_DAI)))
 			return rtd->codec_dai;
@@ -251,6 +248,18 @@
 		.dpcm_capture = 1,
 		.ops = &cht_aif1_ops,
 	},
+	[MERR_DPCM_DEEP_BUFFER] = {
+		.name = "Deep-Buffer Audio Port",
+		.stream_name = "Deep-Buffer Audio",
+		.cpu_dai_name = "deepbuffer-cpu-dai",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.platform_name = "sst-mfld-platform",
+		.nonatomic = true,
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.ops = &cht_aif1_ops,
+	},
 	[MERR_DPCM_COMPR] = {
 		.name = "Compressed Port",
 		.stream_name = "Compress",
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
new file mode 100644
index 0000000..ab7da9c
--- /dev/null
+++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
@@ -0,0 +1,485 @@
+/*
+ * Intel Skylake I2S Machine Driver with MAXIM98357A
+ * and NAU88L25
+ *
+ * Copyright (C) 2015, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../../codecs/nau8825.h"
+
+#define SKL_NUVOTON_CODEC_DAI	"nau8825-hifi"
+#define SKL_MAXIM_CODEC_DAI "HiFi"
+
+static struct snd_soc_jack skylake_headset;
+static struct snd_soc_card skylake_audio_card;
+
+static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card)
+{
+	struct snd_soc_pcm_runtime *rtd;
+
+	list_for_each_entry(rtd, &card->rtd_list, list) {
+
+		if (!strncmp(rtd->codec_dai->name, SKL_NUVOTON_CODEC_DAI,
+			     strlen(SKL_NUVOTON_CODEC_DAI)))
+			return rtd->codec_dai;
+	}
+
+	return NULL;
+}
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *k, int  event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+	struct snd_soc_dai *codec_dai;
+	int ret;
+
+	codec_dai = skl_get_codec_dai(card);
+	if (!codec_dai) {
+		dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
+		return -EIO;
+	}
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		ret = snd_soc_dai_set_sysclk(codec_dai,
+				NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
+		if (ret < 0) {
+			dev_err(card->dev, "set sysclk err = %d\n", ret);
+			return -EIO;
+		}
+	} else {
+		ret = snd_soc_dai_set_sysclk(codec_dai,
+				NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+		if (ret < 0) {
+			dev_err(card->dev, "set sysclk err = %d\n", ret);
+			return -EIO;
+		}
+	}
+
+	return ret;
+}
+
+static const struct snd_kcontrol_new skylake_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+	SOC_DAPM_PIN_SWITCH("Spk"),
+};
+
+static const struct snd_soc_dapm_widget skylake_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_SPK("Spk", NULL),
+	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+	SND_SOC_DAPM_SINK("WoV Sink"),
+	SND_SOC_DAPM_SPK("DP", NULL),
+	SND_SOC_DAPM_SPK("HDMI", NULL),
+	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+			platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route skylake_map[] = {
+	/* HP jack connectors - unknown if we have jack detection */
+	{ "Headphone Jack", NULL, "HPOL" },
+	{ "Headphone Jack", NULL, "HPOR" },
+
+	/* speaker */
+	{ "Spk", NULL, "Speaker" },
+
+	/* other jacks */
+	{ "MIC", NULL, "Headset Mic" },
+	{ "DMic", NULL, "SoC DMIC" },
+
+	{"WoV Sink", NULL, "hwd_in sink"},
+	{"HDMI", NULL, "hif5 Output"},
+	{"DP", NULL, "hif6 Output"},
+
+	/* CODEC BE connections */
+	{ "HiFi Playback", NULL, "ssp0 Tx" },
+	{ "ssp0 Tx", NULL, "codec0_out" },
+
+	{ "Playback", NULL, "ssp1 Tx" },
+	{ "ssp1 Tx", NULL, "codec1_out" },
+
+	{ "codec0_in", NULL, "ssp1 Rx" },
+	{ "ssp1 Rx", NULL, "Capture" },
+
+	/* DMIC */
+	{ "dmic01_hifi", NULL, "DMIC01 Rx" },
+	{ "DMIC01 Rx", NULL, "DMIC AIF" },
+	{ "hifi1", NULL, "iDisp Tx"},
+	{ "iDisp Tx", NULL, "iDisp_out"},
+	{ "Headphone Jack", NULL, "Platform Clock" },
+	{ "Headset Mic", NULL, "Platform Clock" },
+};
+
+static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+	/* The ADSP will covert the FE rate to 48k, stereo */
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	/* set SSP0 to 24 bit */
+	snd_mask_none(fmt);
+	snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+	return 0;
+}
+
+static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int ret;
+	struct snd_soc_codec *codec = rtd->codec;
+
+	/*
+	 * Headset buttons map to the google Reference headset.
+	 * These can be configured by userspace.
+	 */
+	ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack",
+			SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+			SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset,
+			NULL, 0);
+	if (ret) {
+		dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
+		return ret;
+	}
+
+	nau8825_enable_jack_detect(codec, &skylake_headset);
+
+	snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
+	snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
+
+	return ret;
+}
+
+static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_dapm_context *dapm;
+	struct snd_soc_component *component = rtd->cpu_dai->component;
+
+	dapm = snd_soc_component_get_dapm(component);
+	snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
+
+	return 0;
+}
+
+static unsigned int rates[] = {
+	48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_rates = {
+	.count = ARRAY_SIZE(rates),
+	.list  = rates,
+	.mask = 0,
+};
+
+static unsigned int channels[] = {
+	2,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_channels = {
+	.count = ARRAY_SIZE(channels),
+	.list = channels,
+	.mask = 0,
+};
+
+static int skl_fe_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	/*
+	 * On this platform for PCM device we support,
+	 * 48Khz
+	 * stereo
+	 * 16 bit audio
+	 */
+
+	runtime->hw.channels_max = 2;
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+					   &constraints_channels);
+
+	runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+	snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+	snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+
+	return 0;
+}
+
+static const struct snd_soc_ops skylake_nau8825_fe_ops = {
+	.startup = skl_fe_startup,
+};
+
+static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int ret;
+
+	ret = snd_soc_dai_set_sysclk(codec_dai,
+			NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
+
+	if (ret < 0)
+		dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+	return ret;
+}
+
+static struct snd_soc_ops skylake_nau8825_ops = {
+	.hw_params = skylake_nau8825_hw_params,
+};
+
+static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
+		struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *channels = hw_param_interval(params,
+				SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	if (params_channels(params) == 2)
+		channels->min = channels->max = 2;
+	else
+		channels->min = channels->max = 4;
+
+	return 0;
+}
+
+static unsigned int channels_dmic[] = {
+	2, 4,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
+	.count = ARRAY_SIZE(channels_dmic),
+	.list = channels_dmic,
+	.mask = 0,
+};
+
+static int skylake_dmic_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	runtime->hw.channels_max = 4;
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+			&constraints_dmic_channels);
+
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+}
+
+static struct snd_soc_ops skylake_dmic_ops = {
+	.startup = skylake_dmic_startup,
+};
+
+static unsigned int rates_16000[] = {
+	16000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_16000 = {
+	.count = ARRAY_SIZE(rates_16000),
+	.list  = rates_16000,
+};
+
+static int skylake_refcap_startup(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&constraints_16000);
+}
+
+static struct snd_soc_ops skylaye_refcap_ops = {
+	.startup = skylake_refcap_startup,
+};
+
+/* skylake digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link skylake_dais[] = {
+	/* Front End DAI links */
+	{
+		.name = "Skl Audio Port",
+		.stream_name = "Audio",
+		.cpu_dai_name = "System Pin",
+		.platform_name = "0000:00:1f.3",
+		.dynamic = 1,
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.nonatomic = 1,
+		.init = skylake_nau8825_fe_init,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.dpcm_playback = 1,
+		.ops = &skylake_nau8825_fe_ops,
+	},
+	{
+		.name = "Skl Audio Capture Port",
+		.stream_name = "Audio Record",
+		.cpu_dai_name = "System Pin",
+		.platform_name = "0000:00:1f.3",
+		.dynamic = 1,
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.nonatomic = 1,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.dpcm_capture = 1,
+		.ops = &skylake_nau8825_fe_ops,
+	},
+	{
+		.name = "Skl Audio Reference cap",
+		.stream_name = "Wake on Voice",
+		.cpu_dai_name = "Reference Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.init = NULL,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+		.nonatomic = 1,
+		.dynamic = 1,
+		.ops = &skylaye_refcap_ops,
+	},
+	{
+		.name = "Skl Audio DMIC cap",
+		.stream_name = "dmiccap",
+		.cpu_dai_name = "DMIC Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.init = NULL,
+		.dpcm_capture = 1,
+		.nonatomic = 1,
+		.dynamic = 1,
+		.ops = &skylake_dmic_ops,
+	},
+	{
+		.name = "Skl HDMI Port",
+		.stream_name = "Hdmi",
+		.cpu_dai_name = "HDMI Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.dpcm_playback = 1,
+		.init = NULL,
+		.nonatomic = 1,
+		.dynamic = 1,
+	},
+
+	/* Back End DAI links */
+	{
+		/* SSP0 - Codec */
+		.name = "SSP0-Codec",
+		.be_id = 0,
+		.cpu_dai_name = "SSP0 Pin",
+		.platform_name = "0000:00:1f.3",
+		.no_pcm = 1,
+		.codec_name = "MX98357A:00",
+		.codec_dai_name = SKL_MAXIM_CODEC_DAI,
+		.dai_fmt = SND_SOC_DAIFMT_I2S |
+			SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+		.ignore_pmdown_time = 1,
+		.be_hw_params_fixup = skylake_ssp_fixup,
+		.dpcm_playback = 1,
+	},
+	{
+		/* SSP1 - Codec */
+		.name = "SSP1-Codec",
+		.be_id = 0,
+		.cpu_dai_name = "SSP1 Pin",
+		.platform_name = "0000:00:1f.3",
+		.no_pcm = 1,
+		.codec_name = "i2c-10508825:00",
+		.codec_dai_name = SKL_NUVOTON_CODEC_DAI,
+		.init = skylake_nau8825_codec_init,
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+		.ignore_pmdown_time = 1,
+		.be_hw_params_fixup = skylake_ssp_fixup,
+		.ops = &skylake_nau8825_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	{
+		.name = "dmic01",
+		.be_id = 1,
+		.cpu_dai_name = "DMIC01 Pin",
+		.codec_name = "dmic-codec",
+		.codec_dai_name = "dmic-hifi",
+		.platform_name = "0000:00:1f.3",
+		.be_hw_params_fixup = skylake_dmic_fixup,
+		.ignore_suspend = 1,
+		.dpcm_capture = 1,
+		.no_pcm = 1,
+	},
+	{
+		.name = "iDisp",
+		.be_id = 3,
+		.cpu_dai_name = "iDisp Pin",
+		.codec_name = "ehdaudio0D2",
+		.codec_dai_name = "intel-hdmi-hifi1",
+		.platform_name = "0000:00:1f.3",
+		.dpcm_playback = 1,
+		.no_pcm = 1,
+	},
+};
+
+/* skylake audio machine driver for SPT + NAU88L25 */
+static struct snd_soc_card skylake_audio_card = {
+	.name = "sklnau8825max",
+	.owner = THIS_MODULE,
+	.dai_link = skylake_dais,
+	.num_links = ARRAY_SIZE(skylake_dais),
+	.controls = skylake_controls,
+	.num_controls = ARRAY_SIZE(skylake_controls),
+	.dapm_widgets = skylake_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(skylake_widgets),
+	.dapm_routes = skylake_map,
+	.num_dapm_routes = ARRAY_SIZE(skylake_map),
+	.fully_routed = true,
+};
+
+static int skylake_audio_probe(struct platform_device *pdev)
+{
+	skylake_audio_card.dev = &pdev->dev;
+
+	return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
+}
+
+static struct platform_driver skylake_audio = {
+	.probe = skylake_audio_probe,
+	.driver = {
+		.name = "skl_nau88l25_max98357a_i2s",
+		.pm = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(skylake_audio)
+
+/* Module information */
+MODULE_DESCRIPTION("Audio Machine driver-NAU88L25 & MAX98357A in I2S mode");
+MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:skl_nau88l25_max98357a_i2s");
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
new file mode 100644
index 0000000..c071812
--- /dev/null
+++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
@@ -0,0 +1,536 @@
+/*
+ * Intel Skylake I2S Machine Driver for NAU88L25+SSM4567
+ *
+ * Copyright (C) 2015, Intel Corporation. All rights reserved.
+ *
+ * Modified from:
+ *   Intel Skylake I2S Machine Driver for NAU88L25 and SSM4567
+ *
+ *   Copyright (C) 2015, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include "../../codecs/nau8825.h"
+
+#define SKL_NUVOTON_CODEC_DAI	"nau8825-hifi"
+#define SKL_SSM_CODEC_DAI	"ssm4567-hifi"
+
+static struct snd_soc_jack skylake_headset;
+static struct snd_soc_card skylake_audio_card;
+
+static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card)
+{
+	struct snd_soc_pcm_runtime *rtd;
+
+	list_for_each_entry(rtd, &card->rtd_list, list) {
+
+		if (!strncmp(rtd->codec_dai->name, SKL_NUVOTON_CODEC_DAI,
+			     strlen(SKL_NUVOTON_CODEC_DAI)))
+			return rtd->codec_dai;
+	}
+
+	return NULL;
+}
+
+static const struct snd_kcontrol_new skylake_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+	SOC_DAPM_PIN_SWITCH("Left Speaker"),
+	SOC_DAPM_PIN_SWITCH("Right Speaker"),
+};
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *k, int  event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+	struct snd_soc_dai *codec_dai;
+	int ret;
+
+	codec_dai = skl_get_codec_dai(card);
+	if (!codec_dai) {
+		dev_err(card->dev, "Codec dai not found\n");
+		return -EIO;
+	}
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		ret = snd_soc_dai_set_sysclk(codec_dai,
+				NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
+		if (ret < 0) {
+			dev_err(card->dev, "set sysclk err = %d\n", ret);
+			return -EIO;
+		}
+	} else {
+		ret = snd_soc_dai_set_sysclk(codec_dai,
+				NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+		if (ret < 0) {
+			dev_err(card->dev, "set sysclk err = %d\n", ret);
+			return -EIO;
+		}
+	}
+	return ret;
+}
+
+static const struct snd_soc_dapm_widget skylake_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_SPK("Left Speaker", NULL),
+	SND_SOC_DAPM_SPK("Right Speaker", NULL),
+	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+	SND_SOC_DAPM_SINK("WoV Sink"),
+	SND_SOC_DAPM_SPK("DP", NULL),
+	SND_SOC_DAPM_SPK("HDMI", NULL),
+	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+			platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route skylake_map[] = {
+	/* HP jack connectors - unknown if we have jack detection */
+	{"Headphone Jack", NULL, "HPOL"},
+	{"Headphone Jack", NULL, "HPOR"},
+
+	/* speaker */
+	{"Left Speaker", NULL, "Left OUT"},
+	{"Right Speaker", NULL, "Right OUT"},
+
+	/* other jacks */
+	{"MIC", NULL, "Headset Mic"},
+	{"DMic", NULL, "SoC DMIC"},
+
+	{"WoV Sink", NULL, "hwd_in sink"},
+
+	{"HDMI", NULL, "hif5 Output"},
+	{"DP", NULL, "hif6 Output"},
+	/* CODEC BE connections */
+	{ "Left Playback", NULL, "ssp0 Tx"},
+	{ "Right Playback", NULL, "ssp0 Tx"},
+	{ "ssp0 Tx", NULL, "codec0_out"},
+
+	{ "Playback", NULL, "ssp1 Tx"},
+	{ "ssp1 Tx", NULL, "codec1_out"},
+
+	{ "codec0_in", NULL, "ssp1 Rx" },
+	{ "ssp1 Rx", NULL, "Capture" },
+
+	/* DMIC */
+	{ "dmic01_hifi", NULL, "DMIC01 Rx" },
+	{ "DMIC01 Rx", NULL, "DMIC AIF" },
+	{ "hifi1", NULL, "iDisp Tx"},
+	{ "iDisp Tx", NULL, "iDisp_out"},
+	{ "Headphone Jack", NULL, "Platform Clock" },
+	{ "Headset Mic", NULL, "Platform Clock" },
+};
+
+static struct snd_soc_codec_conf ssm4567_codec_conf[] = {
+	{
+		.dev_name = "i2c-INT343B:00",
+		.name_prefix = "Left",
+	},
+	{
+		.dev_name = "i2c-INT343B:01",
+		.name_prefix = "Right",
+	},
+};
+
+static struct snd_soc_dai_link_component ssm4567_codec_components[] = {
+	{ /* Left */
+		.name = "i2c-INT343B:00",
+		.dai_name = SKL_SSM_CODEC_DAI,
+	},
+	{ /* Right */
+		.name = "i2c-INT343B:01",
+		.dai_name = SKL_SSM_CODEC_DAI,
+	},
+};
+
+static int skylake_ssm4567_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int ret;
+
+	/* Slot 1 for left */
+	ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[0], 0x01, 0x01, 2, 48);
+	if (ret < 0)
+		return ret;
+
+	/* Slot 2 for right */
+	ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[1], 0x02, 0x02, 2, 48);
+	if (ret < 0)
+		return ret;
+
+	return ret;
+}
+
+static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int ret;
+	struct snd_soc_codec *codec = rtd->codec;
+
+	/*
+	 * 4 buttons here map to the google Reference headset
+	 * The use of these buttons can be decided by the user space.
+	 */
+	ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack",
+		SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+		SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset,
+		NULL, 0);
+	if (ret) {
+		dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
+		return ret;
+	}
+
+	nau8825_enable_jack_detect(codec, &skylake_headset);
+
+	snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
+	snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
+
+	return ret;
+}
+
+static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_dapm_context *dapm;
+	struct snd_soc_component *component = rtd->cpu_dai->component;
+
+	dapm = snd_soc_component_get_dapm(component);
+	snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
+
+	return 0;
+}
+
+static unsigned int rates[] = {
+	48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_rates = {
+	.count = ARRAY_SIZE(rates),
+	.list  = rates,
+	.mask = 0,
+};
+
+static unsigned int channels[] = {
+	2,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_channels = {
+	.count = ARRAY_SIZE(channels),
+	.list = channels,
+	.mask = 0,
+};
+
+static int skl_fe_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	/*
+	 * on this platform for PCM device we support,
+	 *	48Khz
+	 *	stereo
+	 *	16 bit audio
+	 */
+
+	runtime->hw.channels_max = 2;
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+					   &constraints_channels);
+
+	runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+	snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+	snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+
+	return 0;
+}
+
+static const struct snd_soc_ops skylake_nau8825_fe_ops = {
+	.startup = skl_fe_startup,
+};
+
+static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+						SNDRV_PCM_HW_PARAM_CHANNELS);
+	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+	/* The ADSP will covert the FE rate to 48k, stereo */
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	/* set SSP0 to 24 bit */
+	snd_mask_none(fmt);
+	snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+	return 0;
+}
+
+static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
+			struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *channels = hw_param_interval(params,
+						SNDRV_PCM_HW_PARAM_CHANNELS);
+	if (params_channels(params) == 2)
+		channels->min = channels->max = 2;
+	else
+		channels->min = channels->max = 4;
+
+	return 0;
+}
+
+static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int ret;
+
+	ret = snd_soc_dai_set_sysclk(codec_dai,
+			NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
+
+	if (ret < 0)
+		dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+	return ret;
+}
+
+static struct snd_soc_ops skylake_nau8825_ops = {
+	.hw_params = skylake_nau8825_hw_params,
+};
+
+static unsigned int channels_dmic[] = {
+	2, 4,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
+	.count = ARRAY_SIZE(channels_dmic),
+	.list = channels_dmic,
+	.mask = 0,
+};
+
+static int skylake_dmic_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	runtime->hw.channels_max = 4;
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+			&constraints_dmic_channels);
+
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+}
+
+static struct snd_soc_ops skylake_dmic_ops = {
+	.startup = skylake_dmic_startup,
+};
+
+static unsigned int rates_16000[] = {
+	16000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_16000 = {
+	.count = ARRAY_SIZE(rates_16000),
+	.list  = rates_16000,
+};
+
+static int skylake_refcap_startup(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE,
+			&constraints_16000);
+}
+
+static struct snd_soc_ops skylaye_refcap_ops = {
+	.startup = skylake_refcap_startup,
+};
+
+/* skylake digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link skylake_dais[] = {
+	/* Front End DAI links */
+	{
+		.name = "Skl Audio Port",
+		.stream_name = "Audio",
+		.cpu_dai_name = "System Pin",
+		.platform_name = "0000:00:1f.3",
+		.dynamic = 1,
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.nonatomic = 1,
+		.init = skylake_nau8825_fe_init,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.dpcm_playback = 1,
+		.ops = &skylake_nau8825_fe_ops,
+	},
+	{
+		.name = "Skl Audio Capture Port",
+		.stream_name = "Audio Record",
+		.cpu_dai_name = "System Pin",
+		.platform_name = "0000:00:1f.3",
+		.dynamic = 1,
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.nonatomic = 1,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+		.dpcm_capture = 1,
+		.ops = &skylake_nau8825_fe_ops,
+	},
+	{
+		.name = "Skl Audio Reference cap",
+		.stream_name = "Wake on Voice",
+		.cpu_dai_name = "Reference Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.init = NULL,
+		.dpcm_capture = 1,
+		.ignore_suspend = 1,
+		.nonatomic = 1,
+		.dynamic = 1,
+		.ops = &skylaye_refcap_ops,
+	},
+	{
+		.name = "Skl Audio DMIC cap",
+		.stream_name = "dmiccap",
+		.cpu_dai_name = "DMIC Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.init = NULL,
+		.dpcm_capture = 1,
+		.nonatomic = 1,
+		.dynamic = 1,
+		.ops = &skylake_dmic_ops,
+	},
+	{
+		.name = "Skl HDMI Port",
+		.stream_name = "Hdmi",
+		.cpu_dai_name = "HDMI Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.dpcm_playback = 1,
+		.init = NULL,
+		.nonatomic = 1,
+		.dynamic = 1,
+	},
+
+	/* Back End DAI links */
+	{
+		/* SSP0 - Codec */
+		.name = "SSP0-Codec",
+		.be_id = 0,
+		.cpu_dai_name = "SSP0 Pin",
+		.platform_name = "0000:00:1f.3",
+		.no_pcm = 1,
+		.codecs = ssm4567_codec_components,
+		.num_codecs = ARRAY_SIZE(ssm4567_codec_components),
+		.dai_fmt = SND_SOC_DAIFMT_DSP_A |
+			SND_SOC_DAIFMT_IB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+		.init = skylake_ssm4567_codec_init,
+		.ignore_pmdown_time = 1,
+		.be_hw_params_fixup = skylake_ssp_fixup,
+		.dpcm_playback = 1,
+	},
+	{
+		/* SSP1 - Codec */
+		.name = "SSP1-Codec",
+		.be_id = 0,
+		.cpu_dai_name = "SSP1 Pin",
+		.platform_name = "0000:00:1f.3",
+		.no_pcm = 1,
+		.codec_name = "i2c-10508825:00",
+		.codec_dai_name = SKL_NUVOTON_CODEC_DAI,
+		.init = skylake_nau8825_codec_init,
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+		.ignore_pmdown_time = 1,
+		.be_hw_params_fixup = skylake_ssp_fixup,
+		.ops = &skylake_nau8825_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	{
+		.name = "dmic01",
+		.be_id = 1,
+		.cpu_dai_name = "DMIC01 Pin",
+		.codec_name = "dmic-codec",
+		.codec_dai_name = "dmic-hifi",
+		.platform_name = "0000:00:1f.3",
+		.ignore_suspend = 1,
+		.be_hw_params_fixup = skylake_dmic_fixup,
+		.dpcm_capture = 1,
+		.no_pcm = 1,
+	},
+	{
+		.name = "iDisp",
+		.be_id = 3,
+		.cpu_dai_name = "iDisp Pin",
+		.codec_name = "ehdaudio0D2",
+		.codec_dai_name = "intel-hdmi-hifi1",
+		.platform_name = "0000:00:1f.3",
+		.dpcm_playback = 1,
+		.no_pcm = 1,
+	},
+};
+
+/* skylake audio machine driver for SPT + NAU88L25 */
+static struct snd_soc_card skylake_audio_card = {
+	.name = "sklnau8825adi",
+	.owner = THIS_MODULE,
+	.dai_link = skylake_dais,
+	.num_links = ARRAY_SIZE(skylake_dais),
+	.controls = skylake_controls,
+	.num_controls = ARRAY_SIZE(skylake_controls),
+	.dapm_widgets = skylake_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(skylake_widgets),
+	.dapm_routes = skylake_map,
+	.num_dapm_routes = ARRAY_SIZE(skylake_map),
+	.codec_conf = ssm4567_codec_conf,
+	.num_configs = ARRAY_SIZE(ssm4567_codec_conf),
+	.fully_routed = true,
+};
+
+static int skylake_audio_probe(struct platform_device *pdev)
+{
+	skylake_audio_card.dev = &pdev->dev;
+
+	return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
+}
+
+static struct platform_driver skylake_audio = {
+	.probe = skylake_audio_probe,
+	.driver = {
+		.name = "skl_nau88l25_ssm4567_i2s",
+		.pm = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(skylake_audio)
+
+/* Module information */
+MODULE_AUTHOR("Conrad Cooke  <conrad.cooke@intel.com>");
+MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
+MODULE_AUTHOR("Naveen M <naveen.m@intel.com>");
+MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>");
+MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
+MODULE_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:skl_nau88l25_ssm4567_i2s");
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c
index a73a431..7396ddb 100644
--- a/sound/soc/intel/boards/skl_rt286.c
+++ b/sound/soc/intel/boards/skl_rt286.c
@@ -52,6 +52,7 @@
 	SND_SOC_DAPM_MIC("Mic Jack", NULL),
 	SND_SOC_DAPM_MIC("DMIC2", NULL),
 	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+	SND_SOC_DAPM_SINK("WoV Sink"),
 };
 
 static const struct snd_soc_dapm_route skylake_rt286_map[] = {
@@ -67,7 +68,9 @@
 
 	/* digital mics */
 	{"DMIC1 Pin", NULL, "DMIC2"},
-	{"DMIC AIF", NULL, "SoC DMIC"},
+	{"DMic", NULL, "SoC DMIC"},
+
+	{"WoV Sink", NULL, "hwd_in sink"},
 
 	/* CODEC BE connections */
 	{ "AIF1 Playback", NULL, "ssp0 Tx"},
@@ -79,13 +82,24 @@
 	{ "ssp0 Rx", NULL, "AIF1 Capture" },
 
 	{ "dmic01_hifi", NULL, "DMIC01 Rx" },
-	{ "DMIC01 Rx", NULL, "Capture" },
+	{ "DMIC01 Rx", NULL, "DMIC AIF" },
 
 	{ "hif1", NULL, "iDisp Tx"},
 	{ "iDisp Tx", NULL, "iDisp_out"},
 
 };
 
+static int skylake_rt286_fe_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_dapm_context *dapm;
+	struct snd_soc_component *component = rtd->cpu_dai->component;
+
+	dapm = snd_soc_component_get_dapm(component);
+	snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
+
+	return 0;
+}
+
 static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_codec *codec = rtd->codec;
@@ -101,9 +115,59 @@
 
 	rt286_mic_detect(codec, &skylake_headset);
 
+	snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
+	snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
+
 	return 0;
 }
 
+static unsigned int rates[] = {
+	48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_rates = {
+	.count = ARRAY_SIZE(rates),
+	.list  = rates,
+	.mask = 0,
+};
+
+static unsigned int channels[] = {
+	2,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_channels = {
+	.count = ARRAY_SIZE(channels),
+	.list = channels,
+	.mask = 0,
+};
+
+static int skl_fe_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	/*
+	 * on this platform for PCM device we support,
+	 *	48Khz
+	 *	stereo
+	 *	16 bit audio
+	 */
+
+	runtime->hw.channels_max = 2;
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+					   &constraints_channels);
+
+	runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+	snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+	snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+
+	return 0;
+}
+
+static const struct snd_soc_ops skylake_rt286_fe_ops = {
+	.startup = skl_fe_startup,
+};
 
 static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
 			struct snd_pcm_hw_params *params)
@@ -112,12 +176,15 @@
 			SNDRV_PCM_HW_PARAM_RATE);
 	struct snd_interval *channels = hw_param_interval(params,
 						SNDRV_PCM_HW_PARAM_CHANNELS);
+	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 
 	/* The output is 48KHz, stereo, 16bits */
 	rate->min = rate->max = 48000;
 	channels->min = channels->max = 2;
-	params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
 
+	/* set SSP0 to 24 bit */
+	snd_mask_none(fmt);
+	snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
 	return 0;
 }
 
@@ -140,6 +207,42 @@
 	.hw_params = skylake_rt286_hw_params,
 };
 
+static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *channels = hw_param_interval(params,
+						SNDRV_PCM_HW_PARAM_CHANNELS);
+	channels->min = channels->max = 4;
+
+	return 0;
+}
+
+static unsigned int channels_dmic[] = {
+	2, 4,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
+	.count = ARRAY_SIZE(channels_dmic),
+	.list = channels_dmic,
+	.mask = 0,
+};
+
+static int skylake_dmic_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	runtime->hw.channels_max = 4;
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+					   &constraints_dmic_channels);
+
+	return snd_pcm_hw_constraint_list(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+}
+
+static struct snd_soc_ops skylake_dmic_ops = {
+	.startup = skylake_dmic_startup,
+};
+
 /* skylake digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link skylake_rt286_dais[] = {
 	/* Front End DAI links */
@@ -152,11 +255,13 @@
 		.dynamic = 1,
 		.codec_name = "snd-soc-dummy",
 		.codec_dai_name = "snd-soc-dummy-dai",
+		.init = skylake_rt286_fe_init,
 		.trigger = {
 			SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST
 		},
 		.dpcm_playback = 1,
+		.ops = &skylake_rt286_fe_ops,
 	},
 	{
 		.name = "Skl Audio Capture Port",
@@ -172,6 +277,7 @@
 			SND_SOC_DPCM_TRIGGER_POST
 		},
 		.dpcm_capture = 1,
+		.ops = &skylake_rt286_fe_ops,
 	},
 	{
 		.name = "Skl Audio Reference cap",
@@ -186,6 +292,19 @@
 		.nonatomic = 1,
 		.dynamic = 1,
 	},
+	{
+		.name = "Skl Audio DMIC cap",
+		.stream_name = "dmiccap",
+		.cpu_dai_name = "DMIC Pin",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.platform_name = "0000:00:1f.3",
+		.init = NULL,
+		.dpcm_capture = 1,
+		.nonatomic = 1,
+		.dynamic = 1,
+		.ops = &skylake_dmic_ops,
+	},
 
 	/* Back End DAI links */
 	{
@@ -201,7 +320,6 @@
 		.dai_fmt = SND_SOC_DAIFMT_I2S |
 			SND_SOC_DAIFMT_NB_NF |
 			SND_SOC_DAIFMT_CBS_CFS,
-		.ignore_suspend = 1,
 		.ignore_pmdown_time = 1,
 		.be_hw_params_fixup = skylake_ssp0_fixup,
 		.ops = &skylake_rt286_ops,
@@ -215,6 +333,7 @@
 		.codec_name = "dmic-codec",
 		.codec_dai_name = "dmic-hifi",
 		.platform_name = "0000:00:1f.3",
+		.be_hw_params_fixup = skylake_dmic_fixup,
 		.ignore_suspend = 1,
 		.dpcm_capture = 1,
 		.no_pcm = 1,
@@ -247,6 +366,7 @@
 	.probe = skylake_audio_probe,
 	.driver = {
 		.name = "skl_alc286s_i2s",
+		.pm = &snd_soc_pm_ops,
 	},
 };
 
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index d910558..668fdee 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -1,11 +1,13 @@
 snd-soc-sst-dsp-objs := sst-dsp.o
-snd-soc-sst-acpi-objs := sst-acpi.o
+ifneq ($(CONFIG_SND_SST_IPC_ACPI),)
+snd-soc-sst-acpi-objs := sst-match-acpi.o
+else
+snd-soc-sst-acpi-objs := sst-acpi.o sst-match-acpi.o
+endif
+
 snd-soc-sst-ipc-objs := sst-ipc.o
 
-ifneq ($(CONFIG_DW_DMAC_CORE),)
-snd-soc-sst-dsp-objs += sst-firmware.o
-endif
+snd-soc-sst-dsp-$(CONFIG_DW_DMAC_CORE) += sst-firmware.o
 
 obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
 obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
-
diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c
index 67b6d3d..7a85c57 100644
--- a/sound/soc/intel/common/sst-acpi.c
+++ b/sound/soc/intel/common/sst-acpi.c
@@ -21,21 +21,12 @@
 #include <linux/platform_device.h>
 
 #include "sst-dsp.h"
+#include "sst-acpi.h"
 
 #define SST_LPT_DSP_DMA_ADDR_OFFSET	0x0F0000
 #define SST_WPT_DSP_DMA_ADDR_OFFSET	0x0FE000
 #define SST_LPT_DSP_DMA_SIZE		(1024 - 1)
 
-/* Descriptor for SST ASoC machine driver */
-struct sst_acpi_mach {
-	/* ACPI ID for the matching machine driver. Audio codec for instance */
-	const u8 id[ACPI_ID_LEN];
-	/* machine driver name */
-	const char *drv_name;
-	/* firmware file name */
-	const char *fw_filename;
-};
-
 /* Descriptor for setting up SST platform data */
 struct sst_acpi_desc {
 	const char *drv_name;
@@ -88,28 +79,6 @@
 	return;
 }
 
-static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
-				       void *context, void **ret)
-{
-	*(bool *)context = true;
-	return AE_OK;
-}
-
-static struct sst_acpi_mach *sst_acpi_find_machine(
-	struct sst_acpi_mach *machines)
-{
-	struct sst_acpi_mach *mach;
-	bool found = false;
-
-	for (mach = machines; mach->id[0]; mach++)
-		if (ACPI_SUCCESS(acpi_get_devices(mach->id,
-						  sst_acpi_mach_match,
-						  &found, NULL)) && found)
-			return mach;
-
-	return NULL;
-}
-
 static int sst_acpi_probe(struct platform_device *pdev)
 {
 	const struct acpi_device_id *id;
@@ -211,7 +180,7 @@
 }
 
 static struct sst_acpi_mach haswell_machines[] = {
-	{ "INT33CA", "haswell-audio", "intel/IntcSST1.bin" },
+	{ "INT33CA", "haswell-audio", "intel/IntcSST1.bin", NULL, NULL, NULL },
 	{}
 };
 
@@ -229,7 +198,7 @@
 };
 
 static struct sst_acpi_mach broadwell_machines[] = {
-	{ "INT343A", "broadwell-audio", "intel/IntcSST2.bin" },
+	{ "INT343A", "broadwell-audio", "intel/IntcSST2.bin", NULL, NULL, NULL },
 	{}
 };
 
@@ -247,8 +216,8 @@
 };
 
 static struct sst_acpi_mach baytrail_machines[] = {
-	{ "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
-	{ "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
+	{ "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL },
+	{ "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL },
 	{}
 };
 
diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h
new file mode 100644
index 0000000..3ee3b7a
--- /dev/null
+++ b/sound/soc/intel/common/sst-acpi.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013-15, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/acpi.h>
+
+/* acpi match */
+struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines);
+
+/* Descriptor for SST ASoC machine driver */
+struct sst_acpi_mach {
+	/* ACPI ID for the matching machine driver. Audio codec for instance */
+	const u8 id[ACPI_ID_LEN];
+	/* machine driver name */
+	const char *drv_name;
+	/* firmware file name */
+	const char *fw_filename;
+
+	/* board name */
+	const char *board;
+	void (*machine_quirk)(void);
+	void *pdata;
+};
diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h
index 2151652..81aa1ed 100644
--- a/sound/soc/intel/common/sst-dsp-priv.h
+++ b/sound/soc/intel/common/sst-dsp-priv.h
@@ -243,7 +243,7 @@
 	u32 size;			/* block size */
 	u32 index;			/* block index 0..N */
 	enum sst_mem_type type;		/* block memory type IRAM/DRAM */
-	struct sst_block_ops *ops;	/* block operations, if any */
+	const struct sst_block_ops *ops;/* block operations, if any */
 
 	/* block status */
 	u32 bytes_used;			/* bytes in use by modules */
@@ -308,6 +308,8 @@
 
 	/* SKL data */
 
+	const char *fw_name;
+
 	/* To allocate CL dma buffers */
 	struct skl_dsp_loader_ops dsp_ops;
 	struct skl_dsp_fw_ops fw_ops;
@@ -376,8 +378,8 @@
 
 /* Register the DSPs memory blocks - would be nice to read from ACPI */
 struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
-	u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
-	void *private);
+	u32 size, enum sst_mem_type type, const struct sst_block_ops *ops,
+	u32 index, void *private);
 void sst_mem_block_unregister_all(struct sst_dsp *dsp);
 
 /* Create/Free DMA resources */
diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c
index c9452e0..b5bbdf4 100644
--- a/sound/soc/intel/common/sst-dsp.c
+++ b/sound/soc/intel/common/sst-dsp.c
@@ -420,7 +420,7 @@
 }
 EXPORT_SYMBOL_GPL(sst_dsp_inbox_read);
 
-#if IS_ENABLED(CONFIG_DW_DMAC_CORE)
+#ifdef CONFIG_DW_DMAC_CORE
 struct sst_dsp *sst_dsp_new(struct device *dev,
 	struct sst_dsp_device *sst_dev, struct sst_pdata *pdata)
 {
diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h
index 859f0de..0b84c71 100644
--- a/sound/soc/intel/common/sst-dsp.h
+++ b/sound/soc/intel/common/sst-dsp.h
@@ -216,7 +216,7 @@
 	void *dsp;
 };
 
-#if IS_ENABLED(CONFIG_DW_DMAC_CORE)
+#ifdef CONFIG_DW_DMAC_CORE
 /* Initialization */
 struct sst_dsp *sst_dsp_new(struct device *dev,
 	struct sst_dsp_device *sst_dev, struct sst_pdata *pdata);
diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c
index 1636a1e..ef4881e 100644
--- a/sound/soc/intel/common/sst-firmware.c
+++ b/sound/soc/intel/common/sst-firmware.c
@@ -51,8 +51,22 @@
 
 static inline void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes)
 {
+	u32 tmp = 0;
+	int i, m, n;
+	const u8 *src_byte = src;
+
+	m = bytes / 4;
+	n = bytes % 4;
+
 	/* __iowrite32_copy use 32bit size values so divide by 4 */
-	__iowrite32_copy((void *)dest, src, bytes/4);
+	__iowrite32_copy((void *)dest, src, m);
+
+	if (n) {
+		for (i = 0; i < n; i++)
+			tmp |= (u32)*(src_byte + m * 4 + i) << (i * 8);
+		__iowrite32_copy((void *)(dest + m * 4), &tmp, 1);
+	}
+
 }
 
 static void sst_dma_transfer_complete(void *arg)
@@ -1014,8 +1028,8 @@
 
 /* register a DSP memory block for use with FW based modules */
 struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
-	u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
-	void *private)
+	u32 size, enum sst_mem_type type, const struct sst_block_ops *ops,
+	u32 index, void *private)
 {
 	struct sst_mem_block *block;
 
diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c
new file mode 100644
index 0000000..dd077e1
--- /dev/null
+++ b/sound/soc/intel/common/sst-match-acpi.c
@@ -0,0 +1,43 @@
+/*
+ * sst_match_apci.c - SST (LPE) match for ACPI enumeration.
+ *
+ * Copyright (c) 2013-15, Intel Corporation.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "sst-acpi.h"
+
+static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
+				       void *context, void **ret)
+{
+	*(bool *)context = true;
+	return AE_OK;
+}
+
+struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines)
+{
+	struct sst_acpi_mach *mach;
+	bool found = false;
+
+	for (mach = machines; mach->id[0]; mach++)
+		if (ACPI_SUCCESS(acpi_get_devices(mach->id,
+						  sst_acpi_mach_match,
+						  &found, NULL)) && found)
+			return mach;
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_acpi_find_machine);
diff --git a/sound/soc/intel/haswell/sst-haswell-dsp.c b/sound/soc/intel/haswell/sst-haswell-dsp.c
index 7f94920..b2bec36 100644
--- a/sound/soc/intel/haswell/sst-haswell-dsp.c
+++ b/sound/soc/intel/haswell/sst-haswell-dsp.c
@@ -607,7 +607,7 @@
 	return 0;
 }
 
-static struct sst_block_ops sst_hsw_ops = {
+static const struct sst_block_ops sst_hsw_ops = {
 	.enable = hsw_block_enable,
 	.disable = hsw_block_disable,
 };
diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c
index b27f25f..ac60f13 100644
--- a/sound/soc/intel/haswell/sst-haswell-ipc.c
+++ b/sound/soc/intel/haswell/sst-haswell-ipc.c
@@ -778,7 +778,6 @@
 	struct sst_hsw *hsw = sst_dsp_get_thread_context(sst);
 	struct sst_generic_ipc *ipc = &hsw->ipc;
 	u32 ipcx, ipcd;
-	int handled;
 	unsigned long flags;
 
 	spin_lock_irqsave(&sst->spinlock, flags);
@@ -790,34 +789,30 @@
 	if (ipcx & SST_IPCX_DONE) {
 
 		/* Handle Immediate reply from DSP Core */
-		handled = hsw_process_reply(hsw, ipcx);
+		hsw_process_reply(hsw, ipcx);
 
-		if (handled > 0) {
-			/* clear DONE bit - tell DSP we have completed */
-			sst_dsp_shim_update_bits_unlocked(sst, SST_IPCX,
-				SST_IPCX_DONE, 0);
+		/* clear DONE bit - tell DSP we have completed */
+		sst_dsp_shim_update_bits_unlocked(sst, SST_IPCX,
+			SST_IPCX_DONE, 0);
 
-			/* unmask Done interrupt */
-			sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
-				SST_IMRX_DONE, 0);
-		}
+		/* unmask Done interrupt */
+		sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+			SST_IMRX_DONE, 0);
 	}
 
 	/* new message from DSP */
 	if (ipcd & SST_IPCD_BUSY) {
 
 		/* Handle Notification and Delayed reply from DSP Core */
-		handled = hsw_process_notification(hsw);
+		hsw_process_notification(hsw);
 
 		/* clear BUSY bit and set DONE bit - accept new messages */
-		if (handled > 0) {
-			sst_dsp_shim_update_bits_unlocked(sst, SST_IPCD,
-				SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
+		sst_dsp_shim_update_bits_unlocked(sst, SST_IPCD,
+			SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
 
-			/* unmask busy interrupt */
-			sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
-				SST_IMRX_BUSY, 0);
-		}
+		/* unmask busy interrupt */
+		sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+			SST_IMRX_BUSY, 0);
 	}
 
 	spin_unlock_irqrestore(&sst->spinlock, flags);
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index 50a1095..de6dac4 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -96,7 +96,7 @@
 	}
 
 	ret = skl_sst_dsp_init(bus->dev, mmio_base, irq,
-			loader_ops, &skl->skl_sst);
+			skl->fw_name, loader_ops, &skl->skl_sst);
 	if (ret < 0)
 		return ret;
 
@@ -182,94 +182,6 @@
 	}
 }
 
-static u32 skl_create_channel_map(enum skl_ch_cfg ch_cfg)
-{
-	u32 config;
-
-	switch (ch_cfg) {
-	case SKL_CH_CFG_MONO:
-		config =  (0xFFFFFFF0 | SKL_CHANNEL_LEFT);
-		break;
-
-	case SKL_CH_CFG_STEREO:
-		config = (0xFFFFFF00 | SKL_CHANNEL_LEFT
-			| (SKL_CHANNEL_RIGHT << 4));
-		break;
-
-	case SKL_CH_CFG_2_1:
-		config = (0xFFFFF000 | SKL_CHANNEL_LEFT
-			| (SKL_CHANNEL_RIGHT << 4)
-			| (SKL_CHANNEL_LFE << 8));
-		break;
-
-	case SKL_CH_CFG_3_0:
-		config =  (0xFFFFF000 | SKL_CHANNEL_LEFT
-			| (SKL_CHANNEL_CENTER << 4)
-			| (SKL_CHANNEL_RIGHT << 8));
-		break;
-
-	case SKL_CH_CFG_3_1:
-		config = (0xFFFF0000 | SKL_CHANNEL_LEFT
-			| (SKL_CHANNEL_CENTER << 4)
-			| (SKL_CHANNEL_RIGHT << 8)
-			| (SKL_CHANNEL_LFE << 12));
-		break;
-
-	case SKL_CH_CFG_QUATRO:
-		config = (0xFFFF0000 | SKL_CHANNEL_LEFT
-			| (SKL_CHANNEL_RIGHT << 4)
-			| (SKL_CHANNEL_LEFT_SURROUND << 8)
-			| (SKL_CHANNEL_RIGHT_SURROUND << 12));
-		break;
-
-	case SKL_CH_CFG_4_0:
-		config = (0xFFFF0000 | SKL_CHANNEL_LEFT
-			| (SKL_CHANNEL_CENTER << 4)
-			| (SKL_CHANNEL_RIGHT << 8)
-			| (SKL_CHANNEL_CENTER_SURROUND << 12));
-		break;
-
-	case SKL_CH_CFG_5_0:
-		config = (0xFFF00000 | SKL_CHANNEL_LEFT
-			| (SKL_CHANNEL_CENTER << 4)
-			| (SKL_CHANNEL_RIGHT << 8)
-			| (SKL_CHANNEL_LEFT_SURROUND << 12)
-			| (SKL_CHANNEL_RIGHT_SURROUND << 16));
-		break;
-
-	case SKL_CH_CFG_5_1:
-		config = (0xFF000000 | SKL_CHANNEL_CENTER
-			| (SKL_CHANNEL_LEFT << 4)
-			| (SKL_CHANNEL_RIGHT << 8)
-			| (SKL_CHANNEL_LEFT_SURROUND << 12)
-			| (SKL_CHANNEL_RIGHT_SURROUND << 16)
-			| (SKL_CHANNEL_LFE << 20));
-		break;
-
-	case SKL_CH_CFG_DUAL_MONO:
-		config = (0xFFFFFF00 | SKL_CHANNEL_LEFT
-			| (SKL_CHANNEL_LEFT << 4));
-		break;
-
-	case SKL_CH_CFG_I2S_DUAL_STEREO_0:
-		config = (0xFFFFFF00 | SKL_CHANNEL_LEFT
-			| (SKL_CHANNEL_RIGHT << 4));
-		break;
-
-	case SKL_CH_CFG_I2S_DUAL_STEREO_1:
-		config = (0xFFFF00FF | (SKL_CHANNEL_LEFT << 8)
-			| (SKL_CHANNEL_RIGHT << 12));
-		break;
-
-	default:
-		config =  0xFFFFFFFF;
-		break;
-
-	}
-
-	return config;
-}
-
 /*
  * Each module in DSP expects a base module configuration, which consists of
  * PCM format information, which we calculate in driver and resource values
@@ -280,7 +192,7 @@
 			struct skl_module_cfg *mconfig,
 			struct skl_base_cfg *base_cfg)
 {
-	struct skl_module_fmt *format = &mconfig->in_fmt;
+	struct skl_module_fmt *format = &mconfig->in_fmt[0];
 
 	base_cfg->audio_fmt.number_of_channels = (u8)format->channels;
 
@@ -293,14 +205,14 @@
 			format->bit_depth, format->valid_bit_depth,
 			format->ch_cfg);
 
-	base_cfg->audio_fmt.channel_map = skl_create_channel_map(
-					base_cfg->audio_fmt.ch_cfg);
+	base_cfg->audio_fmt.channel_map = format->ch_map;
 
-	base_cfg->audio_fmt.interleaving = SKL_INTERLEAVING_PER_CHANNEL;
+	base_cfg->audio_fmt.interleaving = format->interleaving_style;
 
 	base_cfg->cps = mconfig->mcps;
 	base_cfg->ibs = mconfig->ibs;
 	base_cfg->obs = mconfig->obs;
+	base_cfg->is_pages = mconfig->mem_pages;
 }
 
 /*
@@ -399,7 +311,7 @@
 			struct skl_module_cfg *mconfig,
 			struct skl_audio_data_format *out_fmt)
 {
-	struct skl_module_fmt *format = &mconfig->out_fmt;
+	struct skl_module_fmt *format = &mconfig->out_fmt[0];
 
 	out_fmt->number_of_channels = (u8)format->channels;
 	out_fmt->s_freq = format->s_freq;
@@ -407,8 +319,9 @@
 	out_fmt->valid_bit_depth = format->valid_bit_depth;
 	out_fmt->ch_cfg = format->ch_cfg;
 
-	out_fmt->channel_map = skl_create_channel_map(out_fmt->ch_cfg);
-	out_fmt->interleaving = SKL_INTERLEAVING_PER_CHANNEL;
+	out_fmt->channel_map = format->ch_map;
+	out_fmt->interleaving = format->interleaving_style;
+	out_fmt->sample_type = format->sample_type;
 
 	dev_dbg(ctx->dev, "copier out format chan=%d fre=%d bitdepth=%d\n",
 		out_fmt->number_of_channels, format->s_freq, format->bit_depth);
@@ -423,7 +336,7 @@
 			struct skl_module_cfg *mconfig,
 			struct skl_src_module_cfg *src_mconfig)
 {
-	struct skl_module_fmt *fmt = &mconfig->out_fmt;
+	struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
 
 	skl_set_base_module_format(ctx, mconfig,
 		(struct skl_base_cfg *)src_mconfig);
@@ -440,7 +353,7 @@
 			struct skl_module_cfg *mconfig,
 			struct skl_up_down_mixer_cfg *mixer_mconfig)
 {
-	struct skl_module_fmt *fmt = &mconfig->out_fmt;
+	struct skl_module_fmt *fmt = &mconfig->out_fmt[0];
 	int i = 0;
 
 	skl_set_base_module_format(ctx,	mconfig,
@@ -475,6 +388,47 @@
 	skl_setup_cpr_gateway_cfg(ctx, mconfig, cpr_mconfig);
 }
 
+/*
+ * Algo module are DSP pre processing modules. Algo module take base module
+ * configuration and params
+ */
+
+static void skl_set_algo_format(struct skl_sst *ctx,
+			struct skl_module_cfg *mconfig,
+			struct skl_algo_cfg *algo_mcfg)
+{
+	struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)algo_mcfg;
+
+	skl_set_base_module_format(ctx, mconfig, base_cfg);
+
+	if (mconfig->formats_config.caps_size == 0)
+		return;
+
+	memcpy(algo_mcfg->params,
+			mconfig->formats_config.caps,
+			mconfig->formats_config.caps_size);
+
+}
+
+/*
+ * Mic select module allows selecting one or many input channels, thus
+ * acting as a demux.
+ *
+ * Mic select module take base module configuration and out-format
+ * configuration
+ */
+static void skl_set_base_outfmt_format(struct skl_sst *ctx,
+			struct skl_module_cfg *mconfig,
+			struct skl_base_outfmt_cfg *base_outfmt_mcfg)
+{
+	struct skl_audio_data_format *out_fmt = &base_outfmt_mcfg->out_fmt;
+	struct skl_base_cfg *base_cfg =
+				(struct skl_base_cfg *)base_outfmt_mcfg;
+
+	skl_set_base_module_format(ctx, mconfig, base_cfg);
+	skl_setup_out_format(ctx, mconfig, out_fmt);
+}
+
 static u16 skl_get_module_param_size(struct skl_sst *ctx,
 			struct skl_module_cfg *mconfig)
 {
@@ -492,6 +446,14 @@
 	case SKL_MODULE_TYPE_UPDWMIX:
 		return sizeof(struct skl_up_down_mixer_cfg);
 
+	case SKL_MODULE_TYPE_ALGO:
+		param_size = sizeof(struct skl_base_cfg);
+		param_size += mconfig->formats_config.caps_size;
+		return param_size;
+
+	case SKL_MODULE_TYPE_BASE_OUTFMT:
+		return sizeof(struct skl_base_outfmt_cfg);
+
 	default:
 		/*
 		 * return only base cfg when no specific module type is
@@ -538,6 +500,14 @@
 		skl_set_updown_mixer_format(ctx, module_config, *param_data);
 		break;
 
+	case SKL_MODULE_TYPE_ALGO:
+		skl_set_algo_format(ctx, module_config, *param_data);
+		break;
+
+	case SKL_MODULE_TYPE_BASE_OUTFMT:
+		skl_set_base_outfmt_format(ctx, module_config, *param_data);
+		break;
+
 	default:
 		skl_set_base_module_format(ctx, module_config, *param_data);
 		break;
@@ -571,10 +541,10 @@
  * In static, the pin_index is fixed based on module_id and instance id
  */
 static int skl_alloc_queue(struct skl_module_pin *mpin,
-			struct skl_module_inst_id id, int max)
+			struct skl_module_cfg *tgt_cfg, int max)
 {
 	int i;
-
+	struct skl_module_inst_id id = tgt_cfg->id;
 	/*
 	 * if pin in dynamic, find first free pin
 	 * otherwise find match module and instance id pin as topology will
@@ -583,16 +553,23 @@
 	 */
 	for (i = 0; i < max; i++)  {
 		if (mpin[i].is_dynamic) {
-			if (!mpin[i].in_use) {
+			if (!mpin[i].in_use &&
+				mpin[i].pin_state == SKL_PIN_UNBIND) {
+
 				mpin[i].in_use = true;
 				mpin[i].id.module_id = id.module_id;
 				mpin[i].id.instance_id = id.instance_id;
+				mpin[i].tgt_mcfg = tgt_cfg;
 				return i;
 			}
 		} else {
 			if (mpin[i].id.module_id == id.module_id &&
-				mpin[i].id.instance_id == id.instance_id)
+				mpin[i].id.instance_id == id.instance_id &&
+				mpin[i].pin_state == SKL_PIN_UNBIND) {
+
+				mpin[i].tgt_mcfg = tgt_cfg;
 				return i;
+			}
 		}
 	}
 
@@ -606,6 +583,28 @@
 		mpin[q_index].id.module_id = 0;
 		mpin[q_index].id.instance_id = 0;
 	}
+	mpin[q_index].pin_state = SKL_PIN_UNBIND;
+	mpin[q_index].tgt_mcfg = NULL;
+}
+
+/* Module state will be set to unint, if all the out pin state is UNBIND */
+
+static void skl_clear_module_state(struct skl_module_pin *mpin, int max,
+						struct skl_module_cfg *mcfg)
+{
+	int i;
+	bool found = false;
+
+	for (i = 0; i < max; i++)  {
+		if (mpin[i].pin_state == SKL_PIN_UNBIND)
+			continue;
+		found = true;
+		break;
+	}
+
+	if (!found)
+		mcfg->m_state = SKL_MODULE_UNINIT;
+	return;
 }
 
 /*
@@ -615,7 +614,7 @@
  * invoke the DSP by sending IPC INIT_INSTANCE using ipc helper
  */
 int skl_init_module(struct skl_sst *ctx,
-			struct skl_module_cfg *mconfig, char *param)
+			struct skl_module_cfg *mconfig)
 {
 	u16 module_config_size = 0;
 	void *param_data = NULL;
@@ -682,37 +681,30 @@
 	struct skl_module_inst_id dst_id = dst_mcfg->id;
 	int in_max = dst_mcfg->max_in_queue;
 	int out_max = src_mcfg->max_out_queue;
-	int src_index, dst_index;
+	int src_index, dst_index, src_pin_state, dst_pin_state;
 
 	skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
 
-	if (src_mcfg->m_state != SKL_MODULE_BIND_DONE)
-		return 0;
-
-	/*
-	 * if intra module unbind, check if both modules are BIND,
-	 * then send unbind
-	 */
-	if ((src_mcfg->pipe->ppl_id != dst_mcfg->pipe->ppl_id) &&
-				dst_mcfg->m_state != SKL_MODULE_BIND_DONE)
-		return 0;
-	else if (src_mcfg->m_state < SKL_MODULE_INIT_DONE &&
-				 dst_mcfg->m_state < SKL_MODULE_INIT_DONE)
-		return 0;
-
 	/* get src queue index */
 	src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max);
 	if (src_index < 0)
 		return -EINVAL;
 
-	msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index;
+	msg.src_queue = src_index;
 
 	/* get dst queue index */
 	dst_index  = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max);
 	if (dst_index < 0)
 		return -EINVAL;
 
-	msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index;
+	msg.dst_queue = dst_index;
+
+	src_pin_state = src_mcfg->m_out_pin[src_index].pin_state;
+	dst_pin_state = dst_mcfg->m_in_pin[dst_index].pin_state;
+
+	if (src_pin_state != SKL_PIN_BIND_DONE ||
+		dst_pin_state != SKL_PIN_BIND_DONE)
+		return 0;
 
 	msg.module_id = src_mcfg->id.module_id;
 	msg.instance_id = src_mcfg->id.instance_id;
@@ -722,10 +714,15 @@
 
 	ret = skl_ipc_bind_unbind(&ctx->ipc, &msg);
 	if (!ret) {
-		src_mcfg->m_state = SKL_MODULE_UNINIT;
 		/* free queue only if unbind is success */
 		skl_free_queue(src_mcfg->m_out_pin, src_index);
 		skl_free_queue(dst_mcfg->m_in_pin, dst_index);
+
+		/*
+		 * check only if src module bind state, bind is
+		 * always from src -> sink
+		 */
+		skl_clear_module_state(src_mcfg->m_out_pin, out_max, src_mcfg);
 	}
 
 	return ret;
@@ -744,8 +741,6 @@
 {
 	int ret;
 	struct skl_ipc_bind_unbind_msg msg;
-	struct skl_module_inst_id src_id = src_mcfg->id;
-	struct skl_module_inst_id dst_id = dst_mcfg->id;
 	int in_max = dst_mcfg->max_in_queue;
 	int out_max = src_mcfg->max_out_queue;
 	int src_index, dst_index;
@@ -756,18 +751,18 @@
 		dst_mcfg->m_state < SKL_MODULE_INIT_DONE)
 		return 0;
 
-	src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_id, out_max);
+	src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_mcfg, out_max);
 	if (src_index < 0)
 		return -EINVAL;
 
-	msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index;
-	dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_id, in_max);
+	msg.src_queue = src_index;
+	dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_mcfg, in_max);
 	if (dst_index < 0) {
 		skl_free_queue(src_mcfg->m_out_pin, src_index);
 		return -EINVAL;
 	}
 
-	msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index;
+	msg.dst_queue = dst_index;
 
 	dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n",
 			 msg.src_queue, msg.dst_queue);
@@ -782,6 +777,8 @@
 
 	if (!ret) {
 		src_mcfg->m_state = SKL_MODULE_BIND_DONE;
+		src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE;
+		dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE;
 	} else {
 		/* error case , if IPC fails, clear the queue index */
 		skl_free_queue(src_mcfg->m_out_pin, src_index);
@@ -852,6 +849,8 @@
 		ret = skl_ipc_delete_pipeline(&ctx->ipc, pipe->ppl_id);
 		if (ret < 0)
 			dev_err(ctx->dev, "Failed to delete pipeline\n");
+
+		pipe->state = SKL_PIPE_INVALID;
 	}
 
 	return ret;
@@ -916,3 +915,30 @@
 
 	return 0;
 }
+
+/* Algo parameter set helper function */
+int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size,
+				u32 param_id, struct skl_module_cfg *mcfg)
+{
+	struct skl_ipc_large_config_msg msg;
+
+	msg.module_id = mcfg->id.module_id;
+	msg.instance_id = mcfg->id.instance_id;
+	msg.param_data_size = size;
+	msg.large_param_id = param_id;
+
+	return skl_ipc_set_large_config(&ctx->ipc, &msg, params);
+}
+
+int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size,
+			  u32 param_id, struct skl_module_cfg *mcfg)
+{
+	struct skl_ipc_large_config_msg msg;
+
+	msg.module_id = mcfg->id.module_id;
+	msg.instance_id = mcfg->id.instance_id;
+	msg.param_data_size = size;
+	msg.large_param_id = param_id;
+
+	return skl_ipc_get_large_config(&ctx->ipc, &msg, params);
+}
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
index b0c7bd1..6e4b21c 100644
--- a/sound/soc/intel/skylake/skl-nhlt.c
+++ b/sound/soc/intel/skylake/skl-nhlt.c
@@ -55,7 +55,7 @@
 
 static struct nhlt_specific_cfg *skl_get_specific_cfg(
 		struct device *dev, struct nhlt_fmt *fmt,
-		u8 no_ch, u32 rate, u16 bps)
+		u8 no_ch, u32 rate, u16 bps, u8 linktype)
 {
 	struct nhlt_specific_cfg *sp_config;
 	struct wav_fmt *wfmt;
@@ -68,11 +68,17 @@
 		wfmt = &fmt_config->fmt_ext.fmt;
 		dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", wfmt->channels,
 			 wfmt->bits_per_sample, wfmt->samples_per_sec);
-		if (wfmt->channels == no_ch && wfmt->samples_per_sec == rate &&
-					wfmt->bits_per_sample == bps) {
+		if (wfmt->channels == no_ch && wfmt->bits_per_sample == bps) {
+			/*
+			 * if link type is dmic ignore rate check as the blob is
+			 * generic for all rates
+			 */
 			sp_config = &fmt_config->config;
+			if (linktype == NHLT_LINK_DMIC)
+				return sp_config;
 
-			return sp_config;
+			if (wfmt->samples_per_sec == rate)
+				return sp_config;
 		}
 
 		fmt_config = (struct nhlt_fmt_cfg *)(fmt_config->config.caps +
@@ -115,7 +121,7 @@
 	struct device *dev = bus->dev;
 	struct nhlt_specific_cfg *sp_config;
 	struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
-	u16 bps = num_ch * s_fmt;
+	u16 bps = (s_fmt == 16) ? 16 : 32;
 	u8 j;
 
 	dump_config(dev, instance, link_type, s_fmt, num_ch, s_rate, dirn, bps);
@@ -128,7 +134,8 @@
 		if (skl_check_ep_match(dev, epnt, instance, link_type, dirn)) {
 			fmt = (struct nhlt_fmt *)(epnt->config.caps +
 						 epnt->config.size);
-			sp_config = skl_get_specific_cfg(dev, fmt, num_ch, s_rate, bps);
+			sp_config = skl_get_specific_cfg(dev, fmt, num_ch,
+							s_rate, bps, link_type);
 			if (sp_config)
 				return sp_config;
 		}
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index a2f94ce..f355325 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -25,9 +25,12 @@
 #include <sound/soc.h>
 #include "skl.h"
 #include "skl-topology.h"
+#include "skl-sst-dsp.h"
+#include "skl-sst-ipc.h"
 
 #define HDA_MONO 1
 #define HDA_STEREO 2
+#define HDA_QUAD 4
 
 static struct snd_pcm_hardware azx_pcm_hw = {
 	.info =			(SNDRV_PCM_INFO_MMAP |
@@ -35,16 +38,20 @@
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				 SNDRV_PCM_INFO_MMAP_VALID |
 				 SNDRV_PCM_INFO_PAUSE |
+				 SNDRV_PCM_INFO_RESUME |
 				 SNDRV_PCM_INFO_SYNC_START |
 				 SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */
 				 SNDRV_PCM_INFO_HAS_LINK_ATIME |
 				 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
-	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
-	.rates =		SNDRV_PCM_RATE_48000,
-	.rate_min =		48000,
+	.formats =		SNDRV_PCM_FMTBIT_S16_LE |
+				SNDRV_PCM_FMTBIT_S32_LE |
+				SNDRV_PCM_FMTBIT_S24_LE,
+	.rates =		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
+				SNDRV_PCM_RATE_8000,
+	.rate_min =		8000,
 	.rate_max =		48000,
-	.channels_min =		2,
-	.channels_max =		2,
+	.channels_min =		1,
+	.channels_max =		HDA_QUAD,
 	.buffer_bytes_max =	AZX_MAX_BUF_SIZE,
 	.period_bytes_min =	128,
 	.period_bytes_max =	AZX_MAX_BUF_SIZE / 2,
@@ -105,6 +112,31 @@
 		return HDAC_EXT_STREAM_TYPE_COUPLED;
 }
 
+/*
+ * check if the stream opened is marked as ignore_suspend by machine, if so
+ * then enable suspend_active refcount
+ *
+ * The count supend_active does not need lock as it is used in open/close
+ * and suspend context
+ */
+static void skl_set_suspend_active(struct snd_pcm_substream *substream,
+					 struct snd_soc_dai *dai, bool enable)
+{
+	struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+	struct snd_soc_dapm_widget *w;
+	struct skl *skl = ebus_to_skl(ebus);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		w = dai->playback_widget;
+	else
+		w = dai->capture_widget;
+
+	if (w->ignore_suspend && enable)
+		skl->supend_active++;
+	else if (w->ignore_suspend && !enable)
+		skl->supend_active--;
+}
+
 static int skl_pcm_open(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
@@ -112,12 +144,8 @@
 	struct hdac_ext_stream *stream;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct skl_dma_params *dma_params;
-	int ret;
 
 	dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
-	ret = pm_runtime_get_sync(dai->dev);
-	if (ret < 0)
-		return ret;
 
 	stream = snd_hdac_ext_stream_assign(ebus, substream,
 					skl_get_host_stream_type(ebus));
@@ -146,6 +174,7 @@
 
 	dev_dbg(dai->dev, "stream tag set in dma params=%d\n",
 				 dma_params->stream_tag);
+	skl_set_suspend_active(substream, dai, true);
 	snd_pcm_set_sync(substream);
 
 	return 0;
@@ -185,10 +214,6 @@
 	int err;
 
 	dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
-	if (hdac_stream(stream)->prepared) {
-		dev_dbg(dai->dev, "already stream is prepared - returning\n");
-		return 0;
-	}
 
 	format_val = skl_get_format(substream, dai);
 	dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n",
@@ -250,6 +275,7 @@
 	struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
 	struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
 	struct skl_dma_params *dma_params = NULL;
+	struct skl *skl = ebus_to_skl(ebus);
 
 	dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
 
@@ -261,9 +287,18 @@
 	 * dma_params
 	 */
 	snd_soc_dai_set_dma_data(dai, substream, NULL);
+	skl_set_suspend_active(substream, dai, false);
 
-	pm_runtime_mark_last_busy(dai->dev);
-	pm_runtime_put_autosuspend(dai->dev);
+	/*
+	 * check if close is for "Reference Pin" and set back the
+	 * CGCTL.MISCBDCGE if disabled by driver
+	 */
+	if (!strncmp(dai->name, "Reference Pin", 13) &&
+			skl->skl_sst->miscbdcg_disabled) {
+		skl->skl_sst->enable_miscbdcge(dai->dev, true);
+		skl->skl_sst->miscbdcg_disabled = false;
+	}
+
 	kfree(dma_params);
 }
 
@@ -291,7 +326,53 @@
 	p_params.ch = params_channels(params);
 	p_params.s_freq = params_rate(params);
 	p_params.stream = substream->stream;
-	skl_tplg_be_update_params(dai, &p_params);
+
+	return skl_tplg_be_update_params(dai, &p_params);
+}
+
+static int skl_decoupled_trigger(struct snd_pcm_substream *substream,
+		int cmd)
+{
+	struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+	struct hdac_bus *bus = ebus_to_hbus(ebus);
+	struct hdac_ext_stream *stream;
+	int start;
+	unsigned long cookie;
+	struct hdac_stream *hstr;
+
+	stream = get_hdac_ext_stream(substream);
+	hstr = hdac_stream(stream);
+
+	if (!hstr->prepared)
+		return -EPIPE;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		start = 1;
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_STOP:
+		start = 0;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&bus->reg_lock, cookie);
+
+	if (start) {
+		snd_hdac_stream_start(hdac_stream(stream), true);
+		snd_hdac_stream_timecounter_init(hstr, 0);
+	} else {
+		snd_hdac_stream_stop(hdac_stream(stream));
+	}
+
+	spin_unlock_irqrestore(&bus->reg_lock, cookie);
 
 	return 0;
 }
@@ -302,23 +383,72 @@
 	struct skl *skl = get_skl_ctx(dai->dev);
 	struct skl_sst *ctx = skl->skl_sst;
 	struct skl_module_cfg *mconfig;
+	struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+	struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+	int ret;
 
 	mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
 	if (!mconfig)
 		return -EIO;
 
 	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 	case SNDRV_PCM_TRIGGER_RESUME:
+		skl_pcm_prepare(substream, dai);
+		/*
+		 * enable DMA Resume enable bit for the stream, set the dpib
+		 * & lpib position to resune before starting the DMA
+		 */
+		snd_hdac_ext_stream_drsm_enable(ebus, true,
+					hdac_stream(stream)->index);
+		snd_hdac_ext_stream_set_dpibr(ebus, stream, stream->dpib);
+		snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
+
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		/*
+		 * Start HOST DMA and Start FE Pipe.This is to make sure that
+		 * there are no underrun/overrun in the case when the FE
+		 * pipeline is started but there is a delay in starting the
+		 * DMA channel on the host.
+		 */
+		snd_hdac_ext_stream_decouple(ebus, stream, true);
+		ret = skl_decoupled_trigger(substream, cmd);
+		if (ret < 0)
+			return ret;
 		return skl_run_pipe(ctx, mconfig->pipe);
+		break;
 
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
-		return skl_stop_pipe(ctx, mconfig->pipe);
+	case SNDRV_PCM_TRIGGER_STOP:
+		/*
+		 * Stop FE Pipe first and stop DMA. This is to make sure that
+		 * there are no underrun/overrun in the case if there is a delay
+		 * between the two operations.
+		 */
+		ret = skl_stop_pipe(ctx, mconfig->pipe);
+		if (ret < 0)
+			return ret;
+
+		ret = skl_decoupled_trigger(substream, cmd);
+		if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) {
+			/* save the dpib and lpib positions */
+			stream->dpib = readl(ebus->bus.remap_addr +
+					AZX_REG_VS_SDXDPIB_XBASE +
+					(AZX_REG_VS_SDXDPIB_XINTERVAL *
+					hdac_stream(stream)->index));
+
+			stream->lpib = snd_hdac_stream_get_pos_lpib(
+							hdac_stream(stream));
+			snd_hdac_ext_stream_decouple(ebus, stream, false);
+		}
+		break;
 
 	default:
-		return 0;
+		return -EINVAL;
 	}
+
+	return 0;
 }
 
 static int skl_link_hw_params(struct snd_pcm_substream *substream,
@@ -352,9 +482,7 @@
 	p_params.stream = substream->stream;
 	p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1;
 
-	skl_tplg_be_update_params(dai, &p_params);
-
-	return 0;
+	return skl_tplg_be_update_params(dai, &p_params);
 }
 
 static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
@@ -369,11 +497,6 @@
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct hdac_ext_link *link;
 
-	if (link_dev->link_prepared) {
-		dev_dbg(dai->dev, "already stream is prepared - returning\n");
-		return 0;
-	}
-
 	dma_params  = (struct skl_dma_params *)
 			snd_soc_dai_get_dma_data(codec_dai, substream);
 	if (dma_params)
@@ -381,14 +504,15 @@
 	dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n",
 			hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name);
 
-	snd_hdac_ext_link_stream_reset(link_dev);
-
-	snd_hdac_ext_link_stream_setup(link_dev, format_val);
-
 	link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name);
 	if (!link)
 		return -EINVAL;
 
+	snd_hdac_ext_bus_link_power_up(link);
+	snd_hdac_ext_link_stream_reset(link_dev);
+
+	snd_hdac_ext_link_stream_setup(link_dev, format_val);
+
 	snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag);
 	link_dev->link_prepared = 1;
 
@@ -400,12 +524,16 @@
 {
 	struct hdac_ext_stream *link_dev =
 				snd_soc_dai_get_dma_data(dai, substream);
+	struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+	struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
 
 	dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
 	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_RESUME:
+		skl_link_pcm_prepare(substream, dai);
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-	case SNDRV_PCM_TRIGGER_RESUME:
+		snd_hdac_ext_stream_decouple(ebus, stream, true);
 		snd_hdac_ext_link_stream_start(link_dev);
 		break;
 
@@ -413,6 +541,8 @@
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_STOP:
 		snd_hdac_ext_link_stream_clear(link_dev);
+		if (cmd == SNDRV_PCM_TRIGGER_SUSPEND)
+			snd_hdac_ext_stream_decouple(ebus, stream, false);
 		break;
 
 	default:
@@ -443,19 +573,6 @@
 	return 0;
 }
 
-static int skl_be_startup(struct snd_pcm_substream *substream,
-		struct snd_soc_dai *dai)
-{
-	return pm_runtime_get_sync(dai->dev);
-}
-
-static void skl_be_shutdown(struct snd_pcm_substream *substream,
-		struct snd_soc_dai *dai)
-{
-	pm_runtime_mark_last_busy(dai->dev);
-	pm_runtime_put_autosuspend(dai->dev);
-}
-
 static struct snd_soc_dai_ops skl_pcm_dai_ops = {
 	.startup = skl_pcm_open,
 	.shutdown = skl_pcm_close,
@@ -466,24 +583,18 @@
 };
 
 static struct snd_soc_dai_ops skl_dmic_dai_ops = {
-	.startup = skl_be_startup,
 	.hw_params = skl_be_hw_params,
-	.shutdown = skl_be_shutdown,
 };
 
 static struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
-	.startup = skl_be_startup,
 	.hw_params = skl_be_hw_params,
-	.shutdown = skl_be_shutdown,
 };
 
 static struct snd_soc_dai_ops skl_link_dai_ops = {
-	.startup = skl_be_startup,
 	.prepare = skl_link_pcm_prepare,
 	.hw_params = skl_link_hw_params,
 	.hw_free = skl_link_hw_free,
 	.trigger = skl_link_pcm_trigger,
-	.shutdown = skl_be_shutdown,
 };
 
 static struct snd_soc_dai_driver skl_platform_dai[] = {
@@ -511,7 +622,7 @@
 	.capture = {
 		.stream_name = "Reference Capture",
 		.channels_min = HDA_MONO,
-		.channels_max = HDA_STEREO,
+		.channels_max = HDA_QUAD,
 		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
 	},
@@ -538,6 +649,18 @@
 		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
 	},
 },
+{
+	.name = "DMIC Pin",
+	.ops = &skl_pcm_dai_ops,
+	.capture = {
+		.stream_name = "DMIC Capture",
+		.channels_min = HDA_MONO,
+		.channels_max = HDA_QUAD,
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+},
+
 /* BE CPU  Dais */
 {
 	.name = "SSP0 Pin",
@@ -558,6 +681,24 @@
 	},
 },
 {
+	.name = "SSP1 Pin",
+	.ops = &skl_be_ssp_dai_ops,
+	.playback = {
+		.stream_name = "ssp1 Tx",
+		.channels_min = HDA_STEREO,
+		.channels_max = HDA_STEREO,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "ssp1 Rx",
+		.channels_min = HDA_STEREO,
+		.channels_max = HDA_STEREO,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+},
+{
 	.name = "iDisp Pin",
 	.ops = &skl_link_dai_ops,
 	.playback = {
@@ -573,8 +714,8 @@
 	.ops = &skl_dmic_dai_ops,
 	.capture = {
 		.stream_name = "DMIC01 Rx",
-		.channels_min = HDA_STEREO,
-		.channels_max = HDA_STEREO,
+		.channels_min = HDA_MONO,
+		.channels_max = HDA_QUAD,
 		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
 	},
@@ -688,66 +829,15 @@
 	return 0;
 }
 
-static int skl_decoupled_trigger(struct snd_pcm_substream *substream,
-		int cmd)
-{
-	struct hdac_ext_bus *ebus = get_bus_ctx(substream);
-	struct hdac_bus *bus = ebus_to_hbus(ebus);
-	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct hdac_ext_stream *stream;
-	int start;
-	unsigned long cookie;
-	struct hdac_stream *hstr;
-
-	dev_dbg(bus->dev, "In %s cmd=%d streamname=%s\n", __func__, cmd, cpu_dai->name);
-
-	stream = get_hdac_ext_stream(substream);
-	hstr = hdac_stream(stream);
-
-	if (!hstr->prepared)
-		return -EPIPE;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-	case SNDRV_PCM_TRIGGER_RESUME:
-		start = 1;
-		break;
-
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_STOP:
-		start = 0;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	spin_lock_irqsave(&bus->reg_lock, cookie);
-
-	if (start)
-		snd_hdac_stream_start(hdac_stream(stream), true);
-	else
-		snd_hdac_stream_stop(hdac_stream(stream));
-
-	if (start)
-		snd_hdac_stream_timecounter_init(hstr, 0);
-
-	spin_unlock_irqrestore(&bus->reg_lock, cookie);
-
-	return 0;
-}
 static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
 					int cmd)
 {
 	struct hdac_ext_bus *ebus = get_bus_ctx(substream);
 
-	if (ebus->ppcap)
-		return skl_decoupled_trigger(substream, cmd);
-	else
+	if (!ebus->ppcap)
 		return skl_coupled_trigger(substream, cmd);
+
+	return 0;
 }
 
 /* calculate runtime delay from LPIB */
@@ -789,7 +879,7 @@
 {
 	struct hdac_stream *hstr = hdac_stream(hstream);
 	struct snd_pcm_substream *substream = hstr->substream;
-	struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+	struct hdac_ext_bus *ebus;
 	unsigned int pos;
 	int delay;
 
@@ -800,6 +890,7 @@
 		pos = 0;
 
 	if (substream->runtime) {
+		ebus = get_bus_ctx(substream);
 		delay = skl_get_delay_from_lpib(ebus, hstream, pos)
 						 + codec_delay;
 		substream->runtime->delay += delay;
@@ -941,7 +1032,6 @@
 	struct skl *skl = ebus_to_skl(ebus);
 
 	INIT_LIST_HEAD(&skl->ppl_list);
-	INIT_LIST_HEAD(&skl->dapm_path_list);
 
 	ret = snd_soc_register_platform(dev, &skl_platform_drv);
 	if (ret) {
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c
index 44748ba..da2329d 100644
--- a/sound/soc/intel/skylake/skl-sst-cldma.c
+++ b/sound/soc/intel/skylake/skl-sst-cldma.c
@@ -18,6 +18,7 @@
 #include <linux/device.h>
 #include <linux/mm.h>
 #include <linux/kthread.h>
+#include <linux/delay.h>
 #include "../common/sst-dsp.h"
 #include "../common/sst-dsp-priv.h"
 
@@ -33,6 +34,53 @@
 			SKL_ADSP_REG_ADSPIC, SKL_ADSPIC_CL_DMA, 0);
 }
 
+static void skl_cldma_stream_run(struct sst_dsp  *ctx, bool enable)
+{
+	unsigned char val;
+	int timeout;
+
+	sst_dsp_shim_update_bits_unlocked(ctx,
+			SKL_ADSP_REG_CL_SD_CTL,
+			CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(enable));
+
+	udelay(3);
+	timeout = 300;
+	do {
+		/* waiting for hardware to report that the stream Run bit set */
+		val = sst_dsp_shim_read(ctx, SKL_ADSP_REG_CL_SD_CTL) &
+			CL_SD_CTL_RUN_MASK;
+		if (enable && val)
+			break;
+		else if (!enable && !val)
+			break;
+		udelay(3);
+	} while (--timeout);
+
+	if (timeout == 0)
+		dev_err(ctx->dev, "Failed to set Run bit=%d enable=%d\n", val, enable);
+}
+
+static void skl_cldma_stream_clear(struct sst_dsp  *ctx)
+{
+	/* make sure Run bit is cleared before setting stream register */
+	skl_cldma_stream_run(ctx, 0);
+
+	sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+				CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0));
+	sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+				CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0));
+	sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+				CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0));
+	sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
+				CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0));
+
+	sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0));
+	sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0);
+
+	sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0);
+	sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0);
+}
+
 /* Code loader helper APIs */
 static void skl_cldma_setup_bdle(struct sst_dsp *ctx,
 		struct snd_dma_buffer *dmab_data,
@@ -68,6 +116,7 @@
 		struct snd_dma_buffer *dmab_bdl, unsigned int max_size,
 		u32 count)
 {
+	skl_cldma_stream_clear(ctx);
 	sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL,
 			CL_SD_BDLPLBA(dmab_bdl->addr));
 	sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU,
@@ -107,36 +156,13 @@
 	sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, 0);
 }
 
-static void skl_cldma_trigger(struct sst_dsp  *ctx, bool enable)
-{
-	if (enable)
-		sst_dsp_shim_update_bits_unlocked(ctx,
-			SKL_ADSP_REG_CL_SD_CTL,
-			CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(1));
-	else
-		sst_dsp_shim_update_bits_unlocked(ctx,
-			SKL_ADSP_REG_CL_SD_CTL,
-			CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(0));
-}
-
 static void skl_cldma_cleanup(struct sst_dsp  *ctx)
 {
 	skl_cldma_cleanup_spb(ctx);
+	skl_cldma_stream_clear(ctx);
 
-	sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
-				CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0));
-	sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
-				CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0));
-	sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
-				CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0));
-	sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
-				CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0));
-
-	sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0));
-	sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0);
-
-	sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0);
-	sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0);
+	ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data);
+	ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl);
 }
 
 static int skl_cldma_wait_interruptible(struct sst_dsp *ctx)
@@ -164,7 +190,7 @@
 
 static void skl_cldma_stop(struct sst_dsp *ctx)
 {
-	ctx->cl_dev.ops.cl_trigger(ctx, false);
+	skl_cldma_stream_run(ctx, false);
 }
 
 static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size,
@@ -175,6 +201,21 @@
 			ctx->cl_dev.dma_buffer_offset, trigger);
 	dev_dbg(ctx->dev, "spib position: %d\n", ctx->cl_dev.curr_spib_pos);
 
+	/*
+	 * Check if the size exceeds buffer boundary. If it exceeds
+	 * max_buffer size, then copy till buffer size and then copy
+	 * remaining buffer from the start of ring buffer.
+	 */
+	if (ctx->cl_dev.dma_buffer_offset + size > ctx->cl_dev.bufsize) {
+		unsigned int size_b = ctx->cl_dev.bufsize -
+					ctx->cl_dev.dma_buffer_offset;
+		memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset,
+			curr_pos, size_b);
+		size -= size_b;
+		curr_pos += size_b;
+		ctx->cl_dev.dma_buffer_offset = 0;
+	}
+
 	memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset,
 			curr_pos, size);
 
@@ -291,7 +332,7 @@
 	ctx->cl_dev.ops.cl_setup_controller = skl_cldma_setup_controller;
 	ctx->cl_dev.ops.cl_setup_spb = skl_cldma_setup_spb;
 	ctx->cl_dev.ops.cl_cleanup_spb = skl_cldma_cleanup_spb;
-	ctx->cl_dev.ops.cl_trigger = skl_cldma_trigger;
+	ctx->cl_dev.ops.cl_trigger = skl_cldma_stream_run;
 	ctx->cl_dev.ops.cl_cleanup_controller = skl_cldma_cleanup;
 	ctx->cl_dev.ops.cl_copy_to_dmabuf = skl_cldma_copy_to_buf;
 	ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop;
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h
index 6bfcef4..cbb4075 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.h
+++ b/sound/soc/intel/skylake/skl-sst-dsp.h
@@ -58,9 +58,9 @@
 
 #define SKL_ADSP_MMIO_LEN		0x10000
 
-#define SKL_ADSP_W0_STAT_SZ		0x800
+#define SKL_ADSP_W0_STAT_SZ		0x1000
 
-#define SKL_ADSP_W0_UP_SZ		0x800
+#define SKL_ADSP_W0_UP_SZ		0x1000
 
 #define SKL_ADSP_W1_SZ			0x1000
 
@@ -114,6 +114,9 @@
 	int (*set_state_D0)(struct sst_dsp *ctx);
 	int (*set_state_D3)(struct sst_dsp *ctx);
 	unsigned int (*get_fw_errcode)(struct sst_dsp *ctx);
+	int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, char *mod_name);
+	int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id);
+
 };
 
 struct skl_dsp_loader_ops {
@@ -123,6 +126,17 @@
 		struct snd_dma_buffer *dmab);
 };
 
+struct skl_load_module_info {
+	u16 mod_id;
+	const struct firmware *fw;
+};
+
+struct skl_module_table {
+	struct skl_load_module_info *mod_info;
+	unsigned int usage_cnt;
+	struct list_head list;
+};
+
 void skl_cldma_process_intr(struct sst_dsp *ctx);
 void skl_cldma_int_disable(struct sst_dsp *ctx);
 int skl_cldma_prepare(struct sst_dsp *ctx);
@@ -139,7 +153,8 @@
 
 int skl_dsp_boot(struct sst_dsp *ctx);
 int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
-		struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp);
+		const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
+		struct skl_sst **dsp);
 void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
 
 #endif /*__SKL_SST_DSP_H__*/
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
index 3345ea0..5434602 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
@@ -16,8 +16,10 @@
 
 #include "../common/sst-dsp.h"
 #include "../common/sst-dsp-priv.h"
+#include "skl.h"
 #include "skl-sst-dsp.h"
 #include "skl-sst-ipc.h"
+#include "sound/hdaudio_ext.h"
 
 
 #define IPC_IXC_STATUS_BITS		24
@@ -130,6 +132,11 @@
 #define IPC_SRC_QUEUE_MASK		0x7
 #define IPC_SRC_QUEUE(x)		(((x) & IPC_SRC_QUEUE_MASK) \
 					<< IPC_SRC_QUEUE_SHIFT)
+/* Load Module count */
+#define IPC_LOAD_MODULE_SHIFT		0
+#define IPC_LOAD_MODULE_MASK		0xFF
+#define IPC_LOAD_MODULE_CNT(x)		(((x) & IPC_LOAD_MODULE_MASK) \
+					<< IPC_LOAD_MODULE_SHIFT)
 
 /* Save pipeline messgae extension register */
 #define IPC_DMA_ID_SHIFT		0
@@ -317,6 +324,19 @@
 			wake_up(&skl->boot_wait);
 			break;
 
+		case IPC_GLB_NOTIFY_PHRASE_DETECTED:
+			dev_dbg(ipc->dev, "***** Phrase Detected **********\n");
+
+			/*
+			 * Per HW recomendation, After phrase detection,
+			 * clear the CGCTL.MISCBDCGE.
+			 *
+			 * This will be set back on stream closure
+			 */
+			skl->enable_miscbdcge(ipc->dev, false);
+			skl->miscbdcg_disabled = true;
+			break;
+
 		default:
 			dev_err(ipc->dev, "ipc: Unhandled error msg=%x",
 						header.primary);
@@ -344,6 +364,8 @@
 	switch (reply) {
 	case IPC_GLB_REPLY_SUCCESS:
 		dev_info(ipc->dev, "ipc FW reply %x: success\n", header.primary);
+		/* copy the rx data from the mailbox */
+		sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size);
 		break;
 
 	case IPC_GLB_REPLY_OUT_OF_MEMORY:
@@ -650,7 +672,7 @@
 	dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
 			 header.primary, header.extension);
 	ret = sst_ipc_tx_message_wait(ipc, *ipc_header,
-				dx, sizeof(dx), NULL, 0);
+				dx, sizeof(*dx), NULL, 0);
 	if (ret < 0) {
 		dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret);
 		return ret;
@@ -728,6 +750,54 @@
 }
 EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind);
 
+/*
+ * In order to load a module we need to send IPC to initiate that. DMA will
+ * performed to load the module memory. The FW supports multiple module load
+ * at single shot, so we can send IPC with N modules represented by
+ * module_cnt
+ */
+int skl_ipc_load_modules(struct sst_generic_ipc *ipc,
+				u8 module_cnt, void *data)
+{
+	struct skl_ipc_header header = {0};
+	u64 *ipc_header = (u64 *)(&header);
+	int ret;
+
+	header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
+	header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+	header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS);
+	header.primary |= IPC_LOAD_MODULE_CNT(module_cnt);
+
+	ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data,
+				(sizeof(u16) * module_cnt), NULL, 0);
+	if (ret < 0)
+		dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_load_modules);
+
+int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt,
+							void *data)
+{
+	struct skl_ipc_header header = {0};
+	u64 *ipc_header = (u64 *)(&header);
+	int ret;
+
+	header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG);
+	header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+	header.primary |= IPC_GLB_TYPE(IPC_GLB_UNLOAD_MULTIPLE_MODS);
+	header.primary |= IPC_LOAD_MODULE_CNT(module_cnt);
+
+	ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data,
+				(sizeof(u16) * module_cnt), NULL, 0);
+	if (ret < 0)
+		dev_err(ipc->dev, "ipc: unload modules failed :%d\n", ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_unload_modules);
+
 int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
 		struct skl_ipc_large_config_msg *msg, u32 *param)
 {
@@ -781,3 +851,54 @@
 	return ret;
 }
 EXPORT_SYMBOL_GPL(skl_ipc_set_large_config);
+
+int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
+		struct skl_ipc_large_config_msg *msg, u32 *param)
+{
+	struct skl_ipc_header header = {0};
+	u64 *ipc_header = (u64 *)(&header);
+	int ret = 0;
+	size_t sz_remaining, rx_size, data_offset;
+
+	header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
+	header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+	header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_GET);
+	header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
+	header.primary |= IPC_MOD_ID(msg->module_id);
+
+	header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size);
+	header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id);
+	header.extension |= IPC_FINAL_BLOCK(1);
+	header.extension |= IPC_INITIAL_BLOCK(1);
+
+	sz_remaining = msg->param_data_size;
+	data_offset = 0;
+
+	while (sz_remaining != 0) {
+		rx_size = sz_remaining > SKL_ADSP_W1_SZ
+				? SKL_ADSP_W1_SZ : sz_remaining;
+		if (rx_size == sz_remaining)
+			header.extension |= IPC_FINAL_BLOCK(1);
+
+		ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0,
+					      ((char *)param) + data_offset,
+					      msg->param_data_size);
+		if (ret < 0) {
+			dev_err(ipc->dev,
+				"ipc: get large config fail, err: %d\n", ret);
+			return ret;
+		}
+		sz_remaining -= rx_size;
+		data_offset = msg->param_data_size - sz_remaining;
+
+		/* clear the fields */
+		header.extension &= IPC_INITIAL_BLOCK_CLEAR;
+		header.extension &= IPC_DATA_OFFSET_SZ_CLEAR;
+		/* fill the fields */
+		header.extension |= IPC_INITIAL_BLOCK(1);
+		header.extension |= IPC_DATA_OFFSET_SZ(data_offset);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_get_large_config);
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
index f1a154e..d59d1ba 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
@@ -55,6 +55,11 @@
 
 	/* IPC messaging */
 	struct sst_generic_ipc ipc;
+
+	/* callback for miscbdge */
+	void (*enable_miscbdcge)(struct device *dev, bool enable);
+	/*Is CGCTL.MISCBDCGE disabled*/
+	bool miscbdcg_disabled;
 };
 
 struct skl_ipc_init_instance_msg {
@@ -108,12 +113,21 @@
 int skl_ipc_bind_unbind(struct sst_generic_ipc *sst_ipc,
 		struct skl_ipc_bind_unbind_msg *msg);
 
+int skl_ipc_load_modules(struct sst_generic_ipc *ipc,
+				u8 module_cnt, void *data);
+
+int skl_ipc_unload_modules(struct sst_generic_ipc *ipc,
+				u8 module_cnt, void *data);
+
 int skl_ipc_set_dx(struct sst_generic_ipc *ipc,
 		u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx);
 
 int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
 		struct skl_ipc_large_config_msg *msg, u32 *param);
 
+int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
+		struct skl_ipc_large_config_msg *msg, u32 *param);
+
 void skl_ipc_int_enable(struct sst_dsp *dsp);
 void skl_ipc_op_int_enable(struct sst_dsp *ctx);
 void skl_ipc_op_int_disable(struct sst_dsp *ctx);
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c
index 3b83dc9..e26f474 100644
--- a/sound/soc/intel/skylake/skl-sst.c
+++ b/sound/soc/intel/skylake/skl-sst.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/err.h>
 #include "../common/sst-dsp.h"
 #include "../common/sst-dsp-priv.h"
 #include "../common/sst-ipc.h"
@@ -37,6 +38,8 @@
 #define SKL_INSTANCE_ID		0
 #define SKL_BASE_FW_MODULE_ID	0
 
+#define SKL_NUM_MODULES		1
+
 static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status)
 {
 	u32 cur_sts;
@@ -77,7 +80,7 @@
 	init_waitqueue_head(&skl->boot_wait);
 
 	if (ctx->fw == NULL) {
-		ret = request_firmware(&ctx->fw, "dsp_fw_release.bin", ctx->dev);
+		ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
 		if (ret < 0) {
 			dev_err(ctx->dev, "Request firmware failed %d\n", ret);
 			skl_dsp_disable_core(ctx);
@@ -115,27 +118,28 @@
 		dev_err(ctx->dev,
 			"Timeout waiting for ROM init done, reg:0x%x\n", reg);
 		ret = -EIO;
-		goto skl_load_base_firmware_failed;
+		goto transfer_firmware_failed;
 	}
 
 	ret = skl_transfer_firmware(ctx, ctx->fw->data, ctx->fw->size);
 	if (ret < 0) {
 		dev_err(ctx->dev, "Transfer firmware failed%d\n", ret);
-		goto skl_load_base_firmware_failed;
+		goto transfer_firmware_failed;
 	} else {
 		ret = wait_event_timeout(skl->boot_wait, skl->boot_complete,
 					msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
 		if (ret == 0) {
 			dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n");
 			ret = -EIO;
-			goto skl_load_base_firmware_failed;
+			goto transfer_firmware_failed;
 		}
 
 		dev_dbg(ctx->dev, "Download firmware successful%d\n", ret);
 		skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
 	}
 	return 0;
-
+transfer_firmware_failed:
+	ctx->cl_dev.ops.cl_cleanup_controller(ctx);
 skl_load_base_firmware_failed:
 	skl_dsp_disable_core(ctx);
 	release_firmware(ctx->fw);
@@ -175,10 +179,15 @@
 	dx.core_mask = SKL_DSP_CORE0_MASK;
 	dx.dx_mask = SKL_IPC_D3_MASK;
 	ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx);
-	if (ret < 0) {
-		dev_err(ctx->dev, "Failed to set DSP to D3 state\n");
-		return ret;
-	}
+	if (ret < 0)
+		dev_err(ctx->dev,
+			"D3 request to FW failed, continuing reset: %d", ret);
+
+	/* disable Interrupt */
+	ctx->cl_dev.ops.cl_cleanup_controller(ctx);
+	skl_cldma_int_disable(ctx);
+	skl_ipc_op_int_disable(ctx);
+	skl_ipc_int_disable(ctx);
 
 	ret = skl_dsp_disable_core(ctx);
 	if (ret < 0) {
@@ -187,12 +196,6 @@
 	}
 	skl_dsp_set_state_locked(ctx, SKL_DSP_RESET);
 
-	/* disable Interrupt */
-	ctx->cl_dev.ops.cl_cleanup_controller(ctx);
-	skl_cldma_int_disable(ctx);
-	skl_ipc_op_int_disable(ctx);
-	skl_ipc_int_disable(ctx);
-
 	return ret;
 }
 
@@ -201,11 +204,182 @@
 	 return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE);
 }
 
+/*
+ * since get/set_module are called from DAPM context,
+ * we don't need lock for usage count
+ */
+static int skl_get_module(struct sst_dsp *ctx, u16 mod_id)
+{
+	struct skl_module_table *module;
+
+	list_for_each_entry(module, &ctx->module_list, list) {
+		if (module->mod_info->mod_id == mod_id)
+			return ++module->usage_cnt;
+	}
+
+	return -EINVAL;
+}
+
+static int skl_put_module(struct sst_dsp *ctx, u16 mod_id)
+{
+	struct skl_module_table *module;
+
+	list_for_each_entry(module, &ctx->module_list, list) {
+		if (module->mod_info->mod_id == mod_id)
+			return --module->usage_cnt;
+	}
+
+	return -EINVAL;
+}
+
+static struct skl_module_table *skl_fill_module_table(struct sst_dsp *ctx,
+						char *mod_name, int mod_id)
+{
+	const struct firmware *fw;
+	struct skl_module_table *skl_module;
+	unsigned int size;
+	int ret;
+
+	ret = request_firmware(&fw, mod_name, ctx->dev);
+	if (ret < 0) {
+		dev_err(ctx->dev, "Request Module %s failed :%d\n",
+							mod_name, ret);
+		return NULL;
+	}
+
+	skl_module = devm_kzalloc(ctx->dev, sizeof(*skl_module), GFP_KERNEL);
+	if (skl_module == NULL) {
+		release_firmware(fw);
+		return NULL;
+	}
+
+	size = sizeof(*skl_module->mod_info);
+	skl_module->mod_info = devm_kzalloc(ctx->dev, size, GFP_KERNEL);
+	if (skl_module->mod_info == NULL) {
+		release_firmware(fw);
+		return NULL;
+	}
+
+	skl_module->mod_info->mod_id = mod_id;
+	skl_module->mod_info->fw = fw;
+	list_add(&skl_module->list, &ctx->module_list);
+
+	return skl_module;
+}
+
+/* get a module from it's unique ID */
+static struct skl_module_table *skl_module_get_from_id(
+			struct sst_dsp *ctx, u16 mod_id)
+{
+	struct skl_module_table *module;
+
+	if (list_empty(&ctx->module_list)) {
+		dev_err(ctx->dev, "Module list is empty\n");
+		return NULL;
+	}
+
+	list_for_each_entry(module, &ctx->module_list, list) {
+		if (module->mod_info->mod_id == mod_id)
+			return module;
+	}
+
+	return NULL;
+}
+
+static int skl_transfer_module(struct sst_dsp *ctx,
+			struct skl_load_module_info *module)
+{
+	int ret;
+	struct skl_sst *skl = ctx->thread_context;
+
+	ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, module->fw->data,
+							module->fw->size);
+	if (ret < 0)
+		return ret;
+
+	ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES,
+						(void *)&module->mod_id);
+	if (ret < 0)
+		dev_err(ctx->dev, "Failed to Load module: %d\n", ret);
+
+	ctx->cl_dev.ops.cl_stop_dma(ctx);
+
+	return ret;
+}
+
+static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, char *guid)
+{
+	struct skl_module_table *module_entry = NULL;
+	int ret = 0;
+	char mod_name[64]; /* guid str = 32 chars + 4 hyphens */
+
+	snprintf(mod_name, sizeof(mod_name), "%s%s%s",
+			"intel/dsp_fw_", guid, ".bin");
+
+	module_entry = skl_module_get_from_id(ctx, mod_id);
+	if (module_entry == NULL) {
+		module_entry = skl_fill_module_table(ctx, mod_name, mod_id);
+		if (module_entry == NULL) {
+			dev_err(ctx->dev, "Failed to Load module\n");
+			return -EINVAL;
+		}
+	}
+
+	if (!module_entry->usage_cnt) {
+		ret = skl_transfer_module(ctx, module_entry->mod_info);
+		if (ret < 0) {
+			dev_err(ctx->dev, "Failed to Load module\n");
+			return ret;
+		}
+	}
+
+	ret = skl_get_module(ctx, mod_id);
+
+	return ret;
+}
+
+static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id)
+{
+	int usage_cnt;
+	struct skl_sst *skl = ctx->thread_context;
+	int ret = 0;
+
+	usage_cnt = skl_put_module(ctx, mod_id);
+	if (usage_cnt < 0) {
+		dev_err(ctx->dev, "Module bad usage cnt!:%d\n", usage_cnt);
+		return -EIO;
+	}
+	ret = skl_ipc_unload_modules(&skl->ipc,
+			SKL_NUM_MODULES, &mod_id);
+	if (ret < 0) {
+		dev_err(ctx->dev, "Failed to UnLoad module\n");
+		skl_get_module(ctx, mod_id);
+		return ret;
+	}
+
+	return ret;
+}
+
+static void skl_clear_module_table(struct sst_dsp *ctx)
+{
+	struct skl_module_table *module, *tmp;
+
+	if (list_empty(&ctx->module_list))
+		return;
+
+	list_for_each_entry_safe(module, tmp, &ctx->module_list, list) {
+		list_del(&module->list);
+		release_firmware(module->mod_info->fw);
+	}
+}
+
 static struct skl_dsp_fw_ops skl_fw_ops = {
 	.set_state_D0 = skl_set_dsp_D0,
 	.set_state_D3 = skl_set_dsp_D3,
 	.load_fw = skl_load_base_firmware,
 	.get_fw_errcode = skl_get_errorcode,
+	.load_mod = skl_load_module,
+	.unload_mod = skl_unload_module,
 };
 
 static struct sst_ops skl_ops = {
@@ -223,7 +397,7 @@
 };
 
 int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
-		struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp)
+		const char *fw_name, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp)
 {
 	struct skl_sst *skl;
 	struct sst_dsp *sst;
@@ -244,11 +418,13 @@
 
 	sst = skl->dsp;
 
+	sst->fw_name = fw_name;
 	sst->addr.lpe = mmio_base;
 	sst->addr.shim = mmio_base;
 	sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
 			SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
 
+	INIT_LIST_HEAD(&sst->module_list);
 	sst->dsp_ops = dsp_ops;
 	sst->fw_ops = skl_fw_ops;
 
@@ -259,23 +435,24 @@
 	ret = sst->fw_ops.load_fw(sst);
 	if (ret < 0) {
 		dev_err(dev, "Load base fw failed : %d", ret);
-		return ret;
+		goto cleanup;
 	}
 
 	if (dsp)
 		*dsp = skl;
 
-	return 0;
+	return ret;
 
-	skl_ipc_free(&skl->ipc);
+cleanup:
+	skl_sst_dsp_cleanup(dev, skl);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
 
 void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
 {
+	skl_clear_module_table(ctx->dsp);
 	skl_ipc_free(&ctx->ipc);
-	ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
 	ctx->dsp->ops->free(ctx->dsp);
 }
 EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup);
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index ad4d0f8..4624556 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -26,6 +26,8 @@
 #include "skl-topology.h"
 #include "skl.h"
 #include "skl-tplg-interface.h"
+#include "../common/sst-dsp.h"
+#include "../common/sst-dsp-priv.h"
 
 #define SKL_CH_FIXUP_MASK		(1 << 0)
 #define SKL_RATE_FIXUP_MASK		(1 << 1)
@@ -129,17 +131,15 @@
 {
 	dev_dbg(ctx->dev, "Dumping config\n");
 	dev_dbg(ctx->dev, "Input Format:\n");
-	dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt.channels);
-	dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt.s_freq);
-	dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt.ch_cfg);
-	dev_dbg(ctx->dev, "valid bit depth = %d\n",
-			mcfg->in_fmt.valid_bit_depth);
+	dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels);
+	dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq);
+	dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg);
+	dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth);
 	dev_dbg(ctx->dev, "Output Format:\n");
-	dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt.channels);
-	dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt.s_freq);
-	dev_dbg(ctx->dev, "valid bit depth = %d\n",
-			mcfg->out_fmt.valid_bit_depth);
-	dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt.ch_cfg);
+	dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels);
+	dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq);
+	dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth);
+	dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg);
 }
 
 static void skl_tplg_update_params(struct skl_module_fmt *fmt,
@@ -149,8 +149,24 @@
 		fmt->s_freq = params->s_freq;
 	if (fixup & SKL_CH_FIXUP_MASK)
 		fmt->channels = params->ch;
-	if (fixup & SKL_FMT_FIXUP_MASK)
-		fmt->valid_bit_depth = params->s_fmt;
+	if (fixup & SKL_FMT_FIXUP_MASK) {
+		fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
+
+		/*
+		 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
+		 * container so update bit depth accordingly
+		 */
+		switch (fmt->valid_bit_depth) {
+		case SKL_DEPTH_16BIT:
+			fmt->bit_depth = fmt->valid_bit_depth;
+			break;
+
+		default:
+			fmt->bit_depth = SKL_DEPTH_32BIT;
+			break;
+		}
+	}
+
 }
 
 /*
@@ -171,8 +187,9 @@
 	int in_fixup, out_fixup;
 	struct skl_module_fmt *in_fmt, *out_fmt;
 
-	in_fmt = &m_cfg->in_fmt;
-	out_fmt = &m_cfg->out_fmt;
+	/* Fixups will be applied to pin 0 only */
+	in_fmt = &m_cfg->in_fmt[0];
+	out_fmt = &m_cfg->out_fmt[0];
 
 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		if (is_fe) {
@@ -209,18 +226,25 @@
 				struct skl_module_cfg *mcfg)
 {
 	int multiplier = 1;
+	struct skl_module_fmt *in_fmt, *out_fmt;
+
+
+	/* Since fixups is applied to pin 0 only, ibs, obs needs
+	 * change for pin 0 only
+	 */
+	in_fmt = &mcfg->in_fmt[0];
+	out_fmt = &mcfg->out_fmt[0];
 
 	if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
 		multiplier = 5;
-
-	mcfg->ibs = (mcfg->in_fmt.s_freq / 1000) *
-				(mcfg->in_fmt.channels) *
-				(mcfg->in_fmt.bit_depth >> 3) *
+	mcfg->ibs = (in_fmt->s_freq / 1000) *
+				(mcfg->in_fmt->channels) *
+				(mcfg->in_fmt->bit_depth >> 3) *
 				multiplier;
 
-	mcfg->obs = (mcfg->out_fmt.s_freq / 1000) *
-				(mcfg->out_fmt.channels) *
-				(mcfg->out_fmt.bit_depth >> 3) *
+	mcfg->obs = (mcfg->out_fmt->s_freq / 1000) *
+				(mcfg->out_fmt->channels) *
+				(mcfg->out_fmt->bit_depth >> 3) *
 				multiplier;
 }
 
@@ -292,6 +316,83 @@
 }
 
 /*
+ * some modules can have multiple params set from user control and
+ * need to be set after module is initialized. If set_param flag is
+ * set module params will be done after module is initialised.
+ */
+static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w,
+						struct skl_sst *ctx)
+{
+	int i, ret;
+	struct skl_module_cfg *mconfig = w->priv;
+	const struct snd_kcontrol_new *k;
+	struct soc_bytes_ext *sb;
+	struct skl_algo_data *bc;
+	struct skl_specific_cfg *sp_cfg;
+
+	if (mconfig->formats_config.caps_size > 0 &&
+		mconfig->formats_config.set_params == SKL_PARAM_SET) {
+		sp_cfg = &mconfig->formats_config;
+		ret = skl_set_module_params(ctx, sp_cfg->caps,
+					sp_cfg->caps_size,
+					sp_cfg->param_id, mconfig);
+		if (ret < 0)
+			return ret;
+	}
+
+	for (i = 0; i < w->num_kcontrols; i++) {
+		k = &w->kcontrol_news[i];
+		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+			sb = (void *) k->private_value;
+			bc = (struct skl_algo_data *)sb->dobj.private;
+
+			if (bc->set_params == SKL_PARAM_SET) {
+				ret = skl_set_module_params(ctx,
+						(u32 *)bc->params, bc->max,
+						bc->param_id, mconfig);
+				if (ret < 0)
+					return ret;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * some module param can set from user control and this is required as
+ * when module is initailzed. if module param is required in init it is
+ * identifed by set_param flag. if set_param flag is not set, then this
+ * parameter needs to set as part of module init.
+ */
+static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
+{
+	const struct snd_kcontrol_new *k;
+	struct soc_bytes_ext *sb;
+	struct skl_algo_data *bc;
+	struct skl_module_cfg *mconfig = w->priv;
+	int i;
+
+	for (i = 0; i < w->num_kcontrols; i++) {
+		k = &w->kcontrol_news[i];
+		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+			sb = (struct soc_bytes_ext *)k->private_value;
+			bc = (struct skl_algo_data *)sb->dobj.private;
+
+			if (bc->set_params != SKL_PARAM_INIT)
+				continue;
+
+			mconfig->formats_config.caps = (u32 *)&bc->params;
+			mconfig->formats_config.caps_size = bc->max;
+
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
  * Inside a pipe instance, we can have various modules. These modules need
  * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
  * skl_init_module() routine, so invoke that for all modules in a pipeline
@@ -313,12 +414,25 @@
 		if (!skl_tplg_alloc_pipe_mcps(skl, mconfig))
 			return -ENOMEM;
 
+		if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) {
+			ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
+				mconfig->id.module_id, mconfig->guid);
+			if (ret < 0)
+				return ret;
+		}
+
 		/*
 		 * apply fix/conversion to module params based on
 		 * FE/BE params
 		 */
 		skl_tplg_update_module_params(w, ctx);
-		ret = skl_init_module(ctx, mconfig, NULL);
+
+		skl_tplg_set_module_init_data(w);
+		ret = skl_init_module(ctx, mconfig);
+		if (ret < 0)
+			return ret;
+
+		ret = skl_tplg_set_module_params(w, ctx);
 		if (ret < 0)
 			return ret;
 	}
@@ -326,6 +440,24 @@
 	return 0;
 }
 
+static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
+	 struct skl_pipe *pipe)
+{
+	struct skl_pipe_module *w_module = NULL;
+	struct skl_module_cfg *mconfig = NULL;
+
+	list_for_each_entry(w_module, &pipe->w_list, node) {
+		mconfig  = w_module->w->priv;
+
+		if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod)
+			return ctx->dsp->fw_ops.unload_mod(ctx->dsp,
+						mconfig->id.module_id);
+	}
+
+	/* no modules to unload in this path, so return */
+	return 0;
+}
+
 /*
  * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
  * need create the pipeline. So we do following:
@@ -397,6 +529,58 @@
 	return 0;
 }
 
+static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
+				struct skl *skl,
+				struct skl_module_cfg *src_mconfig)
+{
+	struct snd_soc_dapm_path *p;
+	struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
+	struct skl_module_cfg *sink_mconfig;
+	struct skl_sst *ctx = skl->skl_sst;
+	int ret;
+
+	snd_soc_dapm_widget_for_each_sink_path(w, p) {
+		if (!p->connect)
+			continue;
+
+		dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name);
+		dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name);
+
+		next_sink = p->sink;
+		/*
+		 * here we will check widgets in sink pipelines, so that
+		 * can be any widgets type and we are only interested if
+		 * they are ones used for SKL so check that first
+		 */
+		if ((p->sink->priv != NULL) &&
+					is_skl_dsp_widget_type(p->sink)) {
+
+			sink = p->sink;
+			sink_mconfig = sink->priv;
+
+			/* Bind source to sink, mixin is always source */
+			ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
+			if (ret)
+				return ret;
+
+			/* Start sinks pipe first */
+			if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
+				if (sink_mconfig->pipe->conn_type !=
+							SKL_PIPE_CONN_TYPE_FE)
+					ret = skl_run_pipe(ctx,
+							sink_mconfig->pipe);
+				if (ret)
+					return ret;
+			}
+		}
+	}
+
+	if (!sink)
+		return skl_tplg_bind_sinks(next_sink, skl, src_mconfig);
+
+	return 0;
+}
+
 /*
  * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
  * we need to do following:
@@ -408,75 +592,62 @@
  *   - Then run current pipe
  */
 static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
-							struct skl *skl)
+								struct skl *skl)
 {
-	struct snd_soc_dapm_path *p;
-	struct skl_dapm_path_list *path_list;
-	struct snd_soc_dapm_widget *source, *sink;
-	struct skl_module_cfg *src_mconfig, *sink_mconfig;
+	struct skl_module_cfg *src_mconfig;
 	struct skl_sst *ctx = skl->skl_sst;
 	int ret = 0;
 
-	source = w;
-	src_mconfig = source->priv;
+	src_mconfig = w->priv;
 
 	/*
 	 * find which sink it is connected to, bind with the sink,
 	 * if sink is not started, start sink pipe first, then start
 	 * this pipe
 	 */
-	snd_soc_dapm_widget_for_each_source_path(w, p) {
-		if (!p->connect)
-			continue;
-
-		dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name);
-		dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name);
-
-		/*
-		 * here we will check widgets in sink pipelines, so that
-		 * can be any widgets type and we are only interested if
-		 * they are ones used for SKL so check that first
-		 */
-		if ((p->sink->priv != NULL) &&
-					is_skl_dsp_widget_type(p->sink)) {
-
-			sink = p->sink;
-			src_mconfig = source->priv;
-			sink_mconfig = sink->priv;
-
-			/* Bind source to sink, mixin is always source */
-			ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
-			if (ret)
-				return ret;
-
-			/* Start sinks pipe first */
-			if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
-				ret = skl_run_pipe(ctx, sink_mconfig->pipe);
-				if (ret)
-					return ret;
-			}
-
-			path_list = kzalloc(
-					sizeof(struct skl_dapm_path_list),
-					GFP_KERNEL);
-			if (path_list == NULL)
-				return -ENOMEM;
-
-			/* Add connected path to one global list */
-			path_list->dapm_path = p;
-			list_add_tail(&path_list->node, &skl->dapm_path_list);
-			break;
-		}
-	}
-
-	/* Start source pipe last after starting all sinks */
-	ret = skl_run_pipe(ctx, src_mconfig->pipe);
+	ret = skl_tplg_bind_sinks(w, skl, src_mconfig);
 	if (ret)
 		return ret;
 
+	/* Start source pipe last after starting all sinks */
+	if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
+		return skl_run_pipe(ctx, src_mconfig->pipe);
+
 	return 0;
 }
 
+static struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
+		struct snd_soc_dapm_widget *w, struct skl *skl)
+{
+	struct snd_soc_dapm_path *p;
+	struct snd_soc_dapm_widget *src_w = NULL;
+	struct skl_sst *ctx = skl->skl_sst;
+
+	snd_soc_dapm_widget_for_each_source_path(w, p) {
+		src_w = p->source;
+		if (!p->connect)
+			continue;
+
+		dev_dbg(ctx->dev, "sink widget=%s\n", w->name);
+		dev_dbg(ctx->dev, "src widget=%s\n", p->source->name);
+
+		/*
+		 * here we will check widgets in sink pipelines, so that can
+		 * be any widgets type and we are only interested if they are
+		 * ones used for SKL so check that first
+		 */
+		if ((p->source->priv != NULL) &&
+					is_skl_dsp_widget_type(p->source)) {
+			return p->source;
+		}
+	}
+
+	if (src_w != NULL)
+		return skl_get_src_dsp_widget(src_w, skl);
+
+	return NULL;
+}
+
 /*
  * in the Post-PMU event of mixer we need to do following:
  *   - Check if this pipe is running
@@ -490,7 +661,6 @@
 							struct skl *skl)
 {
 	int ret = 0;
-	struct snd_soc_dapm_path *p;
 	struct snd_soc_dapm_widget *source, *sink;
 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
 	struct skl_sst *ctx = skl->skl_sst;
@@ -504,32 +674,18 @@
 	 * one more sink before this sink got connected, Since source is
 	 * started, bind this sink to source and start this pipe.
 	 */
-	snd_soc_dapm_widget_for_each_sink_path(w, p) {
-		if (!p->connect)
-			continue;
-
-		dev_dbg(ctx->dev, "sink widget=%s\n", w->name);
-		dev_dbg(ctx->dev, "src widget=%s\n", p->source->name);
+	source = skl_get_src_dsp_widget(w, skl);
+	if (source != NULL) {
+		src_mconfig = source->priv;
+		sink_mconfig = sink->priv;
+		src_pipe_started = 1;
 
 		/*
-		 * here we will check widgets in sink pipelines, so that
-		 * can be any widgets type and we are only interested if
-		 * they are ones used for SKL so check that first
+		 * check pipe state, then no need to bind or start the
+		 * pipe
 		 */
-		if ((p->source->priv != NULL) &&
-					is_skl_dsp_widget_type(p->source)) {
-			source = p->source;
-			src_mconfig = source->priv;
-			sink_mconfig = sink->priv;
-			src_pipe_started = 1;
-
-			/*
-			 * check pipe state, then no need to bind or start
-			 * the pipe
-			 */
-			if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
-				src_pipe_started = 0;
-		}
+		if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
+			src_pipe_started = 0;
 	}
 
 	if (src_pipe_started) {
@@ -537,7 +693,8 @@
 		if (ret)
 			return ret;
 
-		ret = skl_run_pipe(ctx, sink_mconfig->pipe);
+		if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
+			ret = skl_run_pipe(ctx, sink_mconfig->pipe);
 	}
 
 	return ret;
@@ -552,54 +709,37 @@
 static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
 							struct skl *skl)
 {
-	struct snd_soc_dapm_widget *source, *sink;
 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
-	int ret = 0, path_found = 0;
-	struct skl_dapm_path_list *path_list, *tmp_list;
+	int ret = 0, i;
 	struct skl_sst *ctx = skl->skl_sst;
 
-	sink = w;
-	sink_mconfig = sink->priv;
+	sink_mconfig = w->priv;
 
 	/* Stop the pipe */
 	ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
 	if (ret)
 		return ret;
 
-	/*
-	 * This list, dapm_path_list handling here does not need any locks
-	 * as we are under dapm lock while handling widget events.
-	 * List can be manipulated safely only under dapm widgets handler
-	 * routines
-	 */
-	list_for_each_entry_safe(path_list, tmp_list,
-				&skl->dapm_path_list, node) {
-		if (path_list->dapm_path->sink == sink) {
-			dev_dbg(ctx->dev, "Path found = %s\n",
-					path_list->dapm_path->name);
-			source = path_list->dapm_path->source;
-			src_mconfig = source->priv;
-			path_found = 1;
+	for (i = 0; i < sink_mconfig->max_in_queue; i++) {
+		if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
+			src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
+			if (!src_mconfig)
+				continue;
+			/*
+			 * If path_found == 1, that means pmd for source
+			 * pipe has not occurred, source is connected to
+			 * some other sink. so its responsibility of sink
+			 * to unbind itself from source.
+			 */
+			ret = skl_stop_pipe(ctx, src_mconfig->pipe);
+			if (ret < 0)
+				return ret;
 
-			list_del(&path_list->node);
-			kfree(path_list);
-			break;
+			ret = skl_unbind_modules(ctx,
+						src_mconfig, sink_mconfig);
 		}
 	}
 
-	/*
-	 * If path_found == 1, that means pmd for source pipe has
-	 * not occurred, source is connected to some other sink.
-	 * so its responsibility of sink to unbind itself from source.
-	 */
-	if (path_found) {
-		ret = skl_stop_pipe(ctx, src_mconfig->pipe);
-		if (ret < 0)
-			return ret;
-
-		ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig);
-	}
-
 	return ret;
 }
 
@@ -622,10 +762,12 @@
 	int ret = 0;
 
 	skl_tplg_free_pipe_mcps(skl, mconfig);
+	skl_tplg_free_pipe_mem(skl, mconfig);
 
 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
 		dst_module = w_module->w->priv;
 
+		skl_tplg_free_pipe_mcps(skl, dst_module);
 		if (src_module == NULL) {
 			src_module = dst_module;
 			continue;
@@ -639,9 +781,8 @@
 	}
 
 	ret = skl_delete_pipe(ctx, mconfig->pipe);
-	skl_tplg_free_pipe_mem(skl, mconfig);
 
-	return ret;
+	return skl_tplg_unload_pipe_modules(ctx, s_pipe);
 }
 
 /*
@@ -653,47 +794,34 @@
 static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
 								struct skl *skl)
 {
-	struct snd_soc_dapm_widget *source, *sink;
 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
-	int ret = 0, path_found = 0;
-	struct skl_dapm_path_list *path_list, *tmp_path_list;
+	int ret = 0, i;
 	struct skl_sst *ctx = skl->skl_sst;
 
-	source = w;
-	src_mconfig = source->priv;
+	src_mconfig = w->priv;
 
-	skl_tplg_free_pipe_mcps(skl, src_mconfig);
 	/* Stop the pipe since this is a mixin module */
 	ret = skl_stop_pipe(ctx, src_mconfig->pipe);
 	if (ret)
 		return ret;
 
-	list_for_each_entry_safe(path_list, tmp_path_list, &skl->dapm_path_list, node) {
-		if (path_list->dapm_path->source == source) {
-			dev_dbg(ctx->dev, "Path found = %s\n",
-					path_list->dapm_path->name);
-			sink = path_list->dapm_path->sink;
-			sink_mconfig = sink->priv;
-			path_found = 1;
-
-			list_del(&path_list->node);
-			kfree(path_list);
-			break;
+	for (i = 0; i < src_mconfig->max_out_queue; i++) {
+		if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
+			sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
+			if (!sink_mconfig)
+				continue;
+			/*
+			 * This is a connecter and if path is found that means
+			 * unbind between source and sink has not happened yet
+			 */
+			ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
+			if (ret < 0)
+				return ret;
+			ret = skl_unbind_modules(ctx, src_mconfig,
+							sink_mconfig);
 		}
 	}
 
-	/*
-	 * This is a connector and if path is found that means
-	 * unbind between source and sink has not happened yet
-	 */
-	if (path_found) {
-		ret = skl_stop_pipe(ctx, src_mconfig->pipe);
-		if (ret < 0)
-			return ret;
-
-		ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig);
-	}
-
 	return ret;
 }
 
@@ -774,6 +902,67 @@
 	return 0;
 }
 
+static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
+			unsigned int __user *data, unsigned int size)
+{
+	struct soc_bytes_ext *sb =
+			(struct soc_bytes_ext *)kcontrol->private_value;
+	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
+	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct skl_module_cfg *mconfig = w->priv;
+	struct skl *skl = get_skl_ctx(w->dapm->dev);
+
+	if (w->power)
+		skl_get_module_params(skl->skl_sst, (u32 *)bc->params,
+				      bc->max, bc->param_id, mconfig);
+
+	if (bc->params) {
+		if (copy_to_user(data, &bc->param_id, sizeof(u32)))
+			return -EFAULT;
+		if (copy_to_user(data + 1, &size, sizeof(u32)))
+			return -EFAULT;
+		if (copy_to_user(data + 2, bc->params, size))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+#define SKL_PARAM_VENDOR_ID 0xff
+
+static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
+			const unsigned int __user *data, unsigned int size)
+{
+	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
+	struct skl_module_cfg *mconfig = w->priv;
+	struct soc_bytes_ext *sb =
+			(struct soc_bytes_ext *)kcontrol->private_value;
+	struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private;
+	struct skl *skl = get_skl_ctx(w->dapm->dev);
+
+	if (ac->params) {
+		/*
+		 * if the param_is is of type Vendor, firmware expects actual
+		 * parameter id and size from the control.
+		 */
+		if (ac->param_id == SKL_PARAM_VENDOR_ID) {
+			if (copy_from_user(ac->params, data, size))
+				return -EFAULT;
+		} else {
+			if (copy_from_user(ac->params,
+					   data + 2 * sizeof(u32), size))
+				return -EFAULT;
+		}
+
+		if (w->power)
+			return skl_set_module_params(skl->skl_sst,
+						(u32 *)ac->params, ac->max,
+						ac->param_id, mconfig);
+	}
+
+	return 0;
+}
+
 /*
  * The FE params are passed by hw_params of the DAI.
  * On hw_params, the params are stored in Gateway module of the FE and we
@@ -790,9 +979,9 @@
 	memcpy(pipe->p_params, params, sizeof(*params));
 
 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		format = &mconfig->in_fmt;
+		format = &mconfig->in_fmt[0];
 	else
-		format = &mconfig->out_fmt;
+		format = &mconfig->out_fmt[0];
 
 	/* set the hw_params */
 	format->s_freq = params->s_freq;
@@ -809,6 +998,7 @@
 		break;
 
 	case SKL_DEPTH_24BIT:
+	case SKL_DEPTH_32BIT:
 		format->bit_depth = SKL_DEPTH_32BIT;
 		break;
 
@@ -846,7 +1036,7 @@
 		w = dai->playback_widget;
 		snd_soc_dapm_widget_for_each_sink_path(w, p) {
 			if (p->connect && p->sink->power &&
-					is_skl_dsp_widget_type(p->sink))
+					!is_skl_dsp_widget_type(p->sink))
 				continue;
 
 			if (p->sink->priv) {
@@ -859,7 +1049,7 @@
 		w = dai->capture_widget;
 		snd_soc_dapm_widget_for_each_source_path(w, p) {
 			if (p->connect && p->source->power &&
-					is_skl_dsp_widget_type(p->source))
+					!is_skl_dsp_widget_type(p->source))
 				continue;
 
 			if (p->source->priv) {
@@ -920,6 +1110,9 @@
 
 	memcpy(pipe->p_params, params, sizeof(*params));
 
+	if (link_type == NHLT_LINK_HDA)
+		return 0;
+
 	/* update the blob based on virtual bus_id*/
 	cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
 					params->s_fmt, params->ch,
@@ -950,18 +1143,13 @@
 		if (p->connect && is_skl_dsp_widget_type(p->source) &&
 						p->source->priv) {
 
-			if (!p->source->power) {
-				ret = skl_tplg_be_fill_pipe_params(
-						dai, p->source->priv,
-						params);
-				if (ret < 0)
-					return ret;
-			} else {
-				return -EBUSY;
-			}
+			ret = skl_tplg_be_fill_pipe_params(dai,
+						p->source->priv, params);
+			if (ret < 0)
+				return ret;
 		} else {
-			ret = skl_tplg_be_set_src_pipe_params(
-						dai, p->source,	params);
+			ret = skl_tplg_be_set_src_pipe_params(dai,
+						p->source, params);
 			if (ret < 0)
 				return ret;
 		}
@@ -980,15 +1168,10 @@
 		if (p->connect && is_skl_dsp_widget_type(p->sink) &&
 						p->sink->priv) {
 
-			if (!p->sink->power) {
-				ret = skl_tplg_be_fill_pipe_params(
-						dai, p->sink->priv, params);
-				if (ret < 0)
-					return ret;
-			} else {
-				return -EBUSY;
-			}
-
+			ret = skl_tplg_be_fill_pipe_params(dai,
+						p->sink->priv, params);
+			if (ret < 0)
+				return ret;
 		} else {
 			ret = skl_tplg_be_set_sink_pipe_params(
 						dai, p->sink, params);
@@ -1030,6 +1213,11 @@
 	{SKL_PGA_EVENT, skl_tplg_pga_event},
 };
 
+static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
+	{SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get,
+					skl_tplg_tlv_control_set},
+};
+
 /*
  * The topology binary passes the pin info for a module so initialize the pin
  * info passed into module instance
@@ -1045,6 +1233,7 @@
 		m_pin[i].id.instance_id = dfw_pin[i].instance_id;
 		m_pin[i].in_use = false;
 		m_pin[i].is_dynamic = is_dynamic;
+		m_pin[i].pin_state = SKL_PIN_UNBIND;
 	}
 }
 
@@ -1092,6 +1281,24 @@
 	return ppl->pipe;
 }
 
+static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt,
+				struct skl_dfw_module_fmt *src_fmt,
+				int pins)
+{
+	int i;
+
+	for (i = 0; i < pins; i++) {
+		dst_fmt[i].channels  = src_fmt[i].channels;
+		dst_fmt[i].s_freq = src_fmt[i].freq;
+		dst_fmt[i].bit_depth = src_fmt[i].bit_depth;
+		dst_fmt[i].valid_bit_depth = src_fmt[i].valid_bit_depth;
+		dst_fmt[i].ch_cfg = src_fmt[i].ch_cfg;
+		dst_fmt[i].ch_map = src_fmt[i].ch_map;
+		dst_fmt[i].interleaving_style = src_fmt[i].interleaving_style;
+		dst_fmt[i].sample_type = src_fmt[i].sample_type;
+	}
+}
+
 /*
  * Topology core widget load callback
  *
@@ -1130,22 +1337,16 @@
 	mconfig->max_in_queue = dfw_config->max_in_queue;
 	mconfig->max_out_queue = dfw_config->max_out_queue;
 	mconfig->is_loadable = dfw_config->is_loadable;
-	mconfig->in_fmt.channels = dfw_config->in_fmt.channels;
-	mconfig->in_fmt.s_freq = dfw_config->in_fmt.freq;
-	mconfig->in_fmt.bit_depth = dfw_config->in_fmt.bit_depth;
-	mconfig->in_fmt.valid_bit_depth =
-				dfw_config->in_fmt.valid_bit_depth;
-	mconfig->in_fmt.ch_cfg = dfw_config->in_fmt.ch_cfg;
-	mconfig->out_fmt.channels = dfw_config->out_fmt.channels;
-	mconfig->out_fmt.s_freq = dfw_config->out_fmt.freq;
-	mconfig->out_fmt.bit_depth = dfw_config->out_fmt.bit_depth;
-	mconfig->out_fmt.valid_bit_depth =
-				dfw_config->out_fmt.valid_bit_depth;
-	mconfig->out_fmt.ch_cfg = dfw_config->out_fmt.ch_cfg;
+	skl_tplg_fill_fmt(mconfig->in_fmt, dfw_config->in_fmt,
+						MODULE_MAX_IN_PINS);
+	skl_tplg_fill_fmt(mconfig->out_fmt, dfw_config->out_fmt,
+						MODULE_MAX_OUT_PINS);
+
 	mconfig->params_fixup = dfw_config->params_fixup;
 	mconfig->converter = dfw_config->converter;
 	mconfig->m_type = dfw_config->module_type;
 	mconfig->vbus_id = dfw_config->vbus_id;
+	mconfig->mem_pages = dfw_config->mem_pages;
 
 	pipe = skl_tplg_add_pipe(bus->dev, skl, &dfw_config->pipe);
 	if (pipe)
@@ -1156,10 +1357,13 @@
 	mconfig->time_slot = dfw_config->time_slot;
 	mconfig->formats_config.caps_size = dfw_config->caps.caps_size;
 
-	mconfig->m_in_pin = devm_kzalloc(bus->dev,
-				(mconfig->max_in_queue) *
-					sizeof(*mconfig->m_in_pin),
-				GFP_KERNEL);
+	if (dfw_config->is_loadable)
+		memcpy(mconfig->guid, dfw_config->uuid,
+					ARRAY_SIZE(dfw_config->uuid));
+
+	mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) *
+						sizeof(*mconfig->m_in_pin),
+						GFP_KERNEL);
 	if (!mconfig->m_in_pin)
 		return -ENOMEM;
 
@@ -1188,7 +1392,9 @@
 		return -ENOMEM;
 
 	memcpy(mconfig->formats_config.caps, dfw_config->caps.caps,
-					 dfw_config->caps.caps_size);
+						 dfw_config->caps.caps_size);
+	mconfig->formats_config.param_id = dfw_config->caps.param_id;
+	mconfig->formats_config.set_params = dfw_config->caps.set_params;
 
 bind_event:
 	if (tplg_w->event_type == 0) {
@@ -1209,8 +1415,70 @@
 	return 0;
 }
 
+static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
+					struct snd_soc_tplg_bytes_control *bc)
+{
+	struct skl_algo_data *ac;
+	struct skl_dfw_algo_data *dfw_ac =
+				(struct skl_dfw_algo_data *)bc->priv.data;
+
+	ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
+	if (!ac)
+		return -ENOMEM;
+
+	/* Fill private data */
+	ac->max = dfw_ac->max;
+	ac->param_id = dfw_ac->param_id;
+	ac->set_params = dfw_ac->set_params;
+
+	if (ac->max) {
+		ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL);
+		if (!ac->params)
+			return -ENOMEM;
+
+		if (dfw_ac->params)
+			memcpy(ac->params, dfw_ac->params, ac->max);
+	}
+
+	be->dobj.private  = ac;
+	return 0;
+}
+
+static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
+				struct snd_kcontrol_new *kctl,
+				struct snd_soc_tplg_ctl_hdr *hdr)
+{
+	struct soc_bytes_ext *sb;
+	struct snd_soc_tplg_bytes_control *tplg_bc;
+	struct hdac_ext_bus *ebus  = snd_soc_component_get_drvdata(cmpnt);
+	struct hdac_bus *bus = ebus_to_hbus(ebus);
+
+	switch (hdr->ops.info) {
+	case SND_SOC_TPLG_CTL_BYTES:
+		tplg_bc = container_of(hdr,
+				struct snd_soc_tplg_bytes_control, hdr);
+		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+			sb = (struct soc_bytes_ext *)kctl->private_value;
+			if (tplg_bc->priv.size)
+				return skl_init_algo_data(
+						bus->dev, sb, tplg_bc);
+		}
+		break;
+
+	default:
+		dev_warn(bus->dev, "Control load not supported %d:%d:%d\n",
+			hdr->ops.get, hdr->ops.put, hdr->ops.info);
+		break;
+	}
+
+	return 0;
+}
+
 static struct snd_soc_tplg_ops skl_tplg_ops  = {
 	.widget_load = skl_tplg_widget_load,
+	.control_load = skl_tplg_control_load,
+	.bytes_ext_ops = skl_tlv_ops,
+	.bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
 };
 
 /* This will be read from topology manifest, currently defined here */
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index 76053a8..9aa2a2b 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -36,6 +36,9 @@
 /* Maximum number of coefficients up down mixer module */
 #define UP_DOWN_MIXER_MAX_COEFF		6
 
+#define MODULE_MAX_IN_PINS	8
+#define MODULE_MAX_OUT_PINS	8
+
 enum skl_channel_index {
 	SKL_CHANNEL_LEFT = 0,
 	SKL_CHANNEL_RIGHT = 1,
@@ -55,12 +58,6 @@
 	SKL_DEPTH_INVALID
 };
 
-enum skl_interleaving {
-	/* [s1_ch1...s1_chN,...,sM_ch1...sM_chN] */
-	SKL_INTERLEAVING_PER_CHANNEL = 0,
-	/* [s1_ch1...sM_ch1,...,s1_chN...sM_chN] */
-	SKL_INTERLEAVING_PER_SAMPLE = 1,
-};
 
 enum skl_s_freq {
 	SKL_FS_8000 = 8000,
@@ -143,6 +140,16 @@
 	s32 coeff[UP_DOWN_MIXER_MAX_COEFF];
 } __packed;
 
+struct skl_algo_cfg {
+	struct skl_base_cfg  base_cfg;
+	char params[0];
+} __packed;
+
+struct skl_base_outfmt_cfg {
+	struct skl_base_cfg base_cfg;
+	struct skl_audio_data_format out_fmt;
+} __packed;
+
 enum skl_dma_type {
 	SKL_DMA_HDA_HOST_OUTPUT_CLASS = 0,
 	SKL_DMA_HDA_HOST_INPUT_CLASS = 1,
@@ -178,21 +185,34 @@
 	u32 bit_depth;
 	u32 valid_bit_depth;
 	u32 ch_cfg;
+	u32 interleaving_style;
+	u32 sample_type;
+	u32 ch_map;
 };
 
+struct skl_module_cfg;
+
 struct skl_module_inst_id {
 	u32 module_id;
 	u32 instance_id;
 };
 
+enum skl_module_pin_state {
+	SKL_PIN_UNBIND = 0,
+	SKL_PIN_BIND_DONE = 1,
+};
+
 struct skl_module_pin {
 	struct skl_module_inst_id id;
-	u8 pin_index;
 	bool is_dynamic;
 	bool in_use;
+	enum skl_module_pin_state pin_state;
+	struct skl_module_cfg *tgt_mcfg;
 };
 
 struct skl_specific_cfg {
+	u32 set_params;
+	u32 param_id;
 	u32 caps_size;
 	u32 *caps;
 };
@@ -238,9 +258,13 @@
 };
 
 struct skl_module_cfg {
+	char guid[SKL_UUID_STR_SZ];
 	struct skl_module_inst_id id;
-	struct skl_module_fmt in_fmt;
-	struct skl_module_fmt out_fmt;
+	u8 domain;
+	bool homogenous_inputs;
+	bool homogenous_outputs;
+	struct skl_module_fmt in_fmt[MODULE_MAX_IN_PINS];
+	struct skl_module_fmt out_fmt[MODULE_MAX_OUT_PINS];
 	u8 max_in_queue;
 	u8 max_out_queue;
 	u8 in_queue_mask;
@@ -258,6 +282,7 @@
 	u32 params_fixup;
 	u32 converter;
 	u32 vbus_id;
+	u32 mem_pages;
 	struct skl_module_pin *m_in_pin;
 	struct skl_module_pin *m_out_pin;
 	enum skl_module_type m_type;
@@ -267,13 +292,15 @@
 	struct skl_specific_cfg formats_config;
 };
 
-struct skl_pipeline {
-	struct skl_pipe *pipe;
-	struct list_head node;
+struct skl_algo_data {
+	u32 param_id;
+	u32 set_params;
+	u32 max;
+	char *params;
 };
 
-struct skl_dapm_path_list {
-	struct snd_soc_dapm_path *dapm_path;
+struct skl_pipeline {
+	struct skl_pipe *pipe;
 	struct list_head node;
 };
 
@@ -305,8 +332,7 @@
 
 int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
 
-int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config,
-	char *param);
+int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config);
 
 int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg
 	*src_module, struct skl_module_cfg *dst_module);
@@ -314,5 +340,10 @@
 int skl_unbind_modules(struct skl_sst *ctx, struct skl_module_cfg
 	*src_module, struct skl_module_cfg *dst_module);
 
+int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size,
+			u32 param_id, struct skl_module_cfg *mcfg);
+int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size,
+			  u32 param_id, struct skl_module_cfg *mcfg);
+
 enum skl_bitdepth skl_get_bit_depth(int params);
 #endif
diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h
index 2bc396d..c9ae010 100644
--- a/sound/soc/intel/skylake/skl-tplg-interface.h
+++ b/sound/soc/intel/skylake/skl-tplg-interface.h
@@ -23,15 +23,13 @@
  * Default types range from 0~12. type can range from 0 to 0xff
  * SST types start at higher to avoid any overlapping in future
  */
-#define SOC_CONTROL_TYPE_HDA_SST_ALGO_PARAMS	0x100
-#define SOC_CONTROL_TYPE_HDA_SST_MUX		0x101
-#define SOC_CONTROL_TYPE_HDA_SST_MIX		0x101
-#define SOC_CONTROL_TYPE_HDA_SST_BYTE		0x103
+#define SKL_CONTROL_TYPE_BYTE_TLV	0x100
 
 #define HDA_SST_CFG_MAX	900 /* size of copier cfg*/
 #define MAX_IN_QUEUE 8
 #define MAX_OUT_QUEUE 8
 
+#define SKL_UUID_STR_SZ 40
 /* Event types goes here */
 /* Reserve event type 0 for no event handlers */
 enum skl_event_types {
@@ -72,6 +70,7 @@
 	SKL_CH_CFG_DUAL_MONO = 9,
 	SKL_CH_CFG_I2S_DUAL_STEREO_0 = 10,
 	SKL_CH_CFG_I2S_DUAL_STEREO_1 = 11,
+	SKL_CH_CFG_4_CHANNEL = 12,
 	SKL_CH_CFG_INVALID
 };
 
@@ -79,7 +78,9 @@
 	SKL_MODULE_TYPE_MIXER = 0,
 	SKL_MODULE_TYPE_COPIER,
 	SKL_MODULE_TYPE_UPDWMIX,
-	SKL_MODULE_TYPE_SRCINT
+	SKL_MODULE_TYPE_SRCINT,
+	SKL_MODULE_TYPE_ALGO,
+	SKL_MODULE_TYPE_BASE_OUTFMT
 };
 
 enum skl_core_affinity {
@@ -110,6 +111,42 @@
 	SKL_DEVICE_NONE
 };
 
+/**
+ * enum skl_interleaving - interleaving style
+ *
+ * @SKL_INTERLEAVING_PER_CHANNEL: [s1_ch1...s1_chN,...,sM_ch1...sM_chN]
+ * @SKL_INTERLEAVING_PER_SAMPLE: [s1_ch1...sM_ch1,...,s1_chN...sM_chN]
+ */
+enum skl_interleaving {
+	SKL_INTERLEAVING_PER_CHANNEL = 0,
+	SKL_INTERLEAVING_PER_SAMPLE = 1,
+};
+
+enum skl_sample_type {
+	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
+};
+
+enum module_pin_type {
+	/* All pins of the module takes same PCM inputs or outputs
+	* e.g. mixout
+	*/
+	SKL_PIN_TYPE_HOMOGENEOUS,
+	/* All pins of the module takes different PCM inputs or outputs
+	* e.g mux
+	*/
+	SKL_PIN_TYPE_HETEROGENEOUS,
+};
+
+enum skl_module_param_type {
+	SKL_PARAM_DEFAULT = 0,
+	SKL_PARAM_INIT,
+	SKL_PARAM_SET
+};
+
 struct skl_dfw_module_pin {
 	u16 module_id;
 	u16 instance_id;
@@ -121,9 +158,15 @@
 	u32 bit_depth;
 	u32 valid_bit_depth;
 	u32 ch_cfg;
+	u32 interleaving_style;
+	u32 sample_type;
+	u32 ch_map;
 } __packed;
 
 struct skl_dfw_module_caps {
+	u32 set_params:2;
+	u32 rsvd:30;
+	u32 param_id;
 	u32 caps_size;
 	u32 caps[HDA_SST_CFG_MAX];
 };
@@ -131,41 +174,57 @@
 struct skl_dfw_pipe {
 	u8 pipe_id;
 	u8 pipe_priority;
-	u16 conn_type;
-	u32 memory_pages;
+	u16 conn_type:4;
+	u16 rsvd:4;
+	u16 memory_pages:8;
 } __packed;
 
 struct skl_dfw_module {
+	char uuid[SKL_UUID_STR_SZ];
+
 	u16 module_id;
 	u16 instance_id;
 	u32 max_mcps;
-	u8 core_id;
-	u8 max_in_queue;
-	u8 max_out_queue;
-	u8 is_loadable;
-	u8 conn_type;
-	u8 dev_type;
-	u8 hw_conn_type;
-	u8 time_slot;
+	u32 mem_pages;
 	u32 obs;
 	u32 ibs;
-	u32 params_fixup;
-	u32 converter;
-	u32 module_type;
 	u32 vbus_id;
-	u8 is_dynamic_in_pin;
-	u8 is_dynamic_out_pin;
+
+	u32 max_in_queue:8;
+	u32 max_out_queue:8;
+	u32 time_slot:8;
+	u32 core_id:4;
+	u32 rsvd1:4;
+
+	u32 module_type:8;
+	u32 conn_type:4;
+	u32 dev_type:4;
+	u32 hw_conn_type:4;
+	u32 rsvd2:12;
+
+	u32 params_fixup:8;
+	u32 converter:8;
+	u32 input_pin_type:1;
+	u32 output_pin_type:1;
+	u32 is_dynamic_in_pin:1;
+	u32 is_dynamic_out_pin:1;
+	u32 is_loadable:1;
+	u32 rsvd3:11;
+
 	struct skl_dfw_pipe pipe;
-	struct skl_dfw_module_fmt in_fmt;
-	struct skl_dfw_module_fmt out_fmt;
+	struct skl_dfw_module_fmt in_fmt[MAX_IN_QUEUE];
+	struct skl_dfw_module_fmt out_fmt[MAX_OUT_QUEUE];
 	struct skl_dfw_module_pin in_pin[MAX_IN_QUEUE];
 	struct skl_dfw_module_pin out_pin[MAX_OUT_QUEUE];
 	struct skl_dfw_module_caps caps;
 } __packed;
 
 struct skl_dfw_algo_data {
+	u32 set_params:2;
+	u32 rsvd:30;
+	u32 param_id;
 	u32 max;
-	char *params;
+	char params[0];
 } __packed;
 
 #endif
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index caa69c4..443a15d 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -27,7 +27,10 @@
 #include <linux/platform_device.h>
 #include <linux/firmware.h>
 #include <sound/pcm.h>
+#include "../common/sst-acpi.h"
 #include "skl.h"
+#include "skl-sst-dsp.h"
+#include "skl-sst-ipc.h"
 
 /*
  * initialize the PCI registers
@@ -58,6 +61,49 @@
 	skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0);
 }
 
+static void update_pci_dword(struct pci_dev *pci,
+			unsigned int reg, u32 mask, u32 val)
+{
+	u32 data = 0;
+
+	pci_read_config_dword(pci, reg, &data);
+	data &= ~mask;
+	data |= (val & mask);
+	pci_write_config_dword(pci, reg, data);
+}
+
+/*
+ * skl_enable_miscbdcge - enable/dsiable CGCTL.MISCBDCGE bits
+ *
+ * @dev: device pointer
+ * @enable: enable/disable flag
+ */
+static void skl_enable_miscbdcge(struct device *dev, bool enable)
+{
+	struct pci_dev *pci = to_pci_dev(dev);
+	u32 val;
+
+	val = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0;
+
+	update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_MISCBDCGE_MASK, val);
+}
+
+/*
+ * While performing reset, controller may not come back properly causing
+ * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset
+ * (init chip) and then again set CGCTL.MISCBDCGE to 1
+ */
+static int skl_init_chip(struct hdac_bus *bus, bool full_reset)
+{
+	int ret;
+
+	skl_enable_miscbdcge(bus->dev, false);
+	ret = snd_hdac_bus_init_chip(bus, full_reset);
+	skl_enable_miscbdcge(bus->dev, true);
+
+	return ret;
+}
+
 /* called from IRQ */
 static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr)
 {
@@ -130,6 +176,39 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int _skl_suspend(struct hdac_ext_bus *ebus)
+{
+	struct skl *skl = ebus_to_skl(ebus);
+	struct hdac_bus *bus = ebus_to_hbus(ebus);
+	int ret;
+
+	snd_hdac_ext_bus_link_power_down_all(ebus);
+
+	ret = skl_suspend_dsp(skl);
+	if (ret < 0)
+		return ret;
+
+	snd_hdac_bus_stop_chip(bus);
+	skl_enable_miscbdcge(bus->dev, false);
+	snd_hdac_bus_enter_link_reset(bus);
+	skl_enable_miscbdcge(bus->dev, true);
+
+	return 0;
+}
+
+static int _skl_resume(struct hdac_ext_bus *ebus)
+{
+	struct skl *skl = ebus_to_skl(ebus);
+	struct hdac_bus *bus = ebus_to_hbus(ebus);
+
+	skl_init_pci(skl);
+	skl_init_chip(bus, true);
+
+	return skl_resume_dsp(skl);
+}
+#endif
+
 #ifdef CONFIG_PM_SLEEP
 /*
  * power management
@@ -138,26 +217,46 @@
 {
 	struct pci_dev *pci = to_pci_dev(dev);
 	struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+	struct skl *skl  = ebus_to_skl(ebus);
 	struct hdac_bus *bus = ebus_to_hbus(ebus);
 
-	snd_hdac_bus_stop_chip(bus);
-	snd_hdac_bus_enter_link_reset(bus);
-
-	return 0;
+	/*
+	 * Do not suspend if streams which are marked ignore suspend are
+	 * running, we need to save the state for these and continue
+	 */
+	if (skl->supend_active) {
+		snd_hdac_ext_bus_link_power_down_all(ebus);
+		enable_irq_wake(bus->irq);
+		pci_save_state(pci);
+		pci_disable_device(pci);
+		return 0;
+	} else {
+		return _skl_suspend(ebus);
+	}
 }
 
 static int skl_resume(struct device *dev)
 {
 	struct pci_dev *pci = to_pci_dev(dev);
 	struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+	struct skl *skl  = ebus_to_skl(ebus);
 	struct hdac_bus *bus = ebus_to_hbus(ebus);
-	struct skl *hda = ebus_to_skl(ebus);
+	int ret;
 
-	skl_init_pci(hda);
+	/*
+	 * resume only when we are not in suspend active, otherwise need to
+	 * restore the device
+	 */
+	if (skl->supend_active) {
+		pci_restore_state(pci);
+		ret = pci_enable_device(pci);
+		snd_hdac_ext_bus_link_power_up_all(ebus);
+		disable_irq_wake(bus->irq);
+	} else {
+		ret = _skl_resume(ebus);
+	}
 
-	snd_hdac_bus_init_chip(bus, 1);
-
-	return 0;
+	return ret;
 }
 #endif /* CONFIG_PM_SLEEP */
 
@@ -167,24 +266,10 @@
 	struct pci_dev *pci = to_pci_dev(dev);
 	struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
 	struct hdac_bus *bus = ebus_to_hbus(ebus);
-	struct skl *skl = ebus_to_skl(ebus);
-	int ret;
 
 	dev_dbg(bus->dev, "in %s\n", __func__);
 
-	/* enable controller wake up event */
-	snd_hdac_chip_updatew(bus, WAKEEN, 0, STATESTS_INT_MASK);
-
-	snd_hdac_ext_bus_link_power_down_all(ebus);
-
-	ret = skl_suspend_dsp(skl);
-	if (ret < 0)
-		return ret;
-
-	snd_hdac_bus_stop_chip(bus);
-	snd_hdac_bus_enter_link_reset(bus);
-
-	return 0;
+	return _skl_suspend(ebus);
 }
 
 static int skl_runtime_resume(struct device *dev)
@@ -192,20 +277,10 @@
 	struct pci_dev *pci = to_pci_dev(dev);
 	struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
 	struct hdac_bus *bus = ebus_to_hbus(ebus);
-	struct skl *skl = ebus_to_skl(ebus);
-	int status;
 
 	dev_dbg(bus->dev, "in %s\n", __func__);
 
-	/* Read STATESTS before controller reset */
-	status = snd_hdac_chip_readw(bus, STATESTS);
-
-	skl_init_pci(skl);
-	snd_hdac_bus_init_chip(bus, true);
-	/* disable controller Wake Up event */
-	snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0);
-
-	return skl_resume_dsp(skl);
+	return _skl_resume(ebus);
 }
 #endif /* CONFIG_PM */
 
@@ -242,6 +317,43 @@
 	return 0;
 }
 
+static int skl_machine_device_register(struct skl *skl, void *driver_data)
+{
+	struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+	struct platform_device *pdev;
+	struct sst_acpi_mach *mach = driver_data;
+	int ret;
+
+	mach = sst_acpi_find_machine(mach);
+	if (mach == NULL) {
+		dev_err(bus->dev, "No matching machine driver found\n");
+		return -ENODEV;
+	}
+	skl->fw_name = mach->fw_filename;
+
+	pdev = platform_device_alloc(mach->drv_name, -1);
+	if (pdev == NULL) {
+		dev_err(bus->dev, "platform device alloc failed\n");
+		return -EIO;
+	}
+
+	ret = platform_device_add(pdev);
+	if (ret) {
+		dev_err(bus->dev, "failed to add machine device\n");
+		platform_device_put(pdev);
+		return -EIO;
+	}
+	skl->i2s_dev = pdev;
+
+	return 0;
+}
+
+static void skl_machine_device_unregister(struct skl *skl)
+{
+	if (skl->i2s_dev)
+		platform_device_unregister(skl->i2s_dev);
+}
+
 static int skl_dmic_device_register(struct skl *skl)
 {
 	struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
@@ -321,7 +433,7 @@
 				 * back to the sanity state.
 				 */
 				snd_hdac_bus_stop_chip(bus);
-				snd_hdac_bus_init_chip(bus, true);
+				skl_init_chip(bus, true);
 			}
 		}
 	}
@@ -431,12 +543,11 @@
 	/* initialize chip */
 	skl_init_pci(skl);
 
-	snd_hdac_bus_init_chip(bus, true);
+	skl_init_chip(bus, true);
 
 	/* codec detection */
 	if (!bus->codec_mask) {
-		dev_err(bus->dev, "no codecs found!\n");
-		return -ENODEV;
+		dev_info(bus->dev, "no hda codecs found!\n");
 	}
 
 	return 0;
@@ -471,11 +582,18 @@
 
 	/* check if dsp is there */
 	if (ebus->ppcap) {
+		err = skl_machine_device_register(skl,
+				  (void *)pci_id->driver_data);
+		if (err < 0)
+			goto out_free;
+
 		err = skl_init_dsp(skl);
 		if (err < 0) {
 			dev_dbg(bus->dev, "error failed to register dsp\n");
-			goto out_free;
+			goto out_mach_free;
 		}
+		skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
+
 	}
 	if (ebus->mlcap)
 		snd_hdac_ext_bus_get_ml_capabilities(ebus);
@@ -509,6 +627,8 @@
 	skl_dmic_device_unregister(skl);
 out_dsp_free:
 	skl_free_dsp(skl);
+out_mach_free:
+	skl_machine_device_unregister(skl);
 out_free:
 	skl->init_failed = 1;
 	skl_free(ebus);
@@ -529,15 +649,26 @@
 	pci_dev_put(pci);
 	skl_platform_unregister(&pci->dev);
 	skl_free_dsp(skl);
+	skl_machine_device_unregister(skl);
 	skl_dmic_device_unregister(skl);
 	skl_free(ebus);
 	dev_set_drvdata(&pci->dev, NULL);
 }
 
+static struct sst_acpi_mach sst_skl_devdata[] = {
+	{ "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL },
+	{ "INT343B", "skl_nau88l25_ssm4567_i2s", "intel/dsp_fw_release.bin",
+				NULL, NULL, NULL },
+	{ "MX98357A", "skl_nau88l25_max98357a_i2s", "intel/dsp_fw_release.bin",
+				NULL, NULL, NULL },
+	{}
+};
+
 /* PCI IDs */
 static const struct pci_device_id skl_ids[] = {
 	/* Sunrise Point-LP */
-	{ PCI_DEVICE(0x8086, 0x9d70), 0},
+	{ PCI_DEVICE(0x8086, 0x9d70),
+		.driver_data = (unsigned long)&sst_skl_devdata},
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, skl_ids);
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index a0709e3..4d18293 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -48,6 +48,9 @@
 #define AZX_REG_VS_SDXEFIFOS_XBASE	0x1094
 #define AZX_REG_VS_SDXEFIFOS_XINTERVAL	0x20
 
+#define AZX_PCIREG_CGCTL		0x48
+#define AZX_CGCTL_MISCBDCGE_MASK	(1 << 6)
+
 struct skl_dsp_resource {
 	u32 max_mcps;
 	u32 max_mem;
@@ -61,15 +64,18 @@
 
 	unsigned int init_failed:1; /* delayed init failed */
 	struct platform_device *dmic_dev;
+	struct platform_device *i2s_dev;
 
 	void *nhlt; /* nhlt ptr */
 	struct skl_sst *skl_sst; /* sst skl ctx */
 
 	struct skl_dsp_resource resource;
 	struct list_head ppl_list;
-	struct list_head dapm_path_list;
 
+	const char *fw_name;
 	const struct firmware *tplg;
+
+	int supend_active;
 };
 
 #define skl_to_ebus(s)	(&(s)->ebus)
diff --git a/sound/soc/mediatek/mtk-afe-common.h b/sound/soc/mediatek/mtk-afe-common.h
index cc4393c..9b1af1a 100644
--- a/sound/soc/mediatek/mtk-afe-common.h
+++ b/sound/soc/mediatek/mtk-afe-common.h
@@ -92,7 +92,6 @@
 struct mtk_afe_memif {
 	unsigned int phys_buf_addr;
 	int buffer_size;
-	unsigned int hw_ptr;		/* Previous IRQ's HW ptr */
 	struct snd_pcm_substream *substream;
 	const struct mtk_afe_memif_data *data;
 	const struct mtk_afe_irq_data *irqdata;
diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c
index f5baf3c..08af9f5 100644
--- a/sound/soc/mediatek/mtk-afe-pcm.c
+++ b/sound/soc/mediatek/mtk-afe-pcm.c
@@ -175,8 +175,17 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
 	struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+	unsigned int hw_ptr;
+	int ret;
 
-	return bytes_to_frames(substream->runtime, memif->hw_ptr);
+	ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur, &hw_ptr);
+	if (ret || hw_ptr == 0) {
+		dev_err(afe->dev, "%s hw_ptr err\n", __func__);
+		hw_ptr = memif->phys_buf_addr;
+	}
+
+	return bytes_to_frames(substream->runtime,
+			       hw_ptr - memif->phys_buf_addr);
 }
 
 static const struct snd_pcm_ops mtk_afe_pcm_ops = {
@@ -299,8 +308,6 @@
 			dev_err(afe->dev, "Failed to enable m_ck\n");
 			return ret;
 		}
-		regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
-				   AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0);
 	}
 
 	if (b_ck) {
@@ -340,12 +347,8 @@
 static void mtk_afe_dais_disable_clks(struct mtk_afe *afe,
 				      struct clk *m_ck, struct clk *b_ck)
 {
-	if (m_ck) {
-		regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
-				   AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M,
-				   AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M);
+	if (m_ck)
 		clk_disable_unprepare(m_ck);
-	}
 	if (b_ck)
 		clk_disable_unprepare(b_ck);
 }
@@ -360,6 +363,8 @@
 		return 0;
 
 	mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+			   AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0);
 	return 0;
 }
 
@@ -373,10 +378,10 @@
 		return;
 
 	mtk_afe_set_i2s_enable(afe, false);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+			   AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M,
+			   AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M);
 	mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL);
-
-	/* disable AFE */
-	regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0);
 }
 
 static int mtk_afe_i2s_prepare(struct snd_pcm_substream *substream,
@@ -425,9 +430,6 @@
 
 	mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S3_M],
 				  afe->clocks[MTK_CLK_I2S3_B]);
-
-	/* disable AFE */
-	regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0);
 }
 
 static int mtk_afe_hdmi_prepare(struct snd_pcm_substream *substream,
@@ -603,7 +605,6 @@
 
 	memif->phys_buf_addr = substream->runtime->dma_addr;
 	memif->buffer_size = substream->runtime->dma_bytes;
-	memif->hw_ptr = 0;
 
 	/* start */
 	regmap_write(afe->regmap,
@@ -672,17 +673,6 @@
 	return snd_pcm_lib_free_pages(substream);
 }
 
-static int mtk_afe_dais_prepare(struct snd_pcm_substream *substream,
-				struct snd_soc_dai *dai)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
-
-	/* enable AFE */
-	regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1);
-	return 0;
-}
-
 static int mtk_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd,
 				struct snd_soc_dai *dai)
 {
@@ -738,7 +728,6 @@
 		/* and clear pending IRQ */
 		regmap_write(afe->regmap, AFE_IRQ_CLR,
 			     1 << memif->data->irq_clr_shift);
-		memif->hw_ptr = 0;
 		return 0;
 	default:
 		return -EINVAL;
@@ -751,7 +740,6 @@
 	.shutdown	= mtk_afe_dais_shutdown,
 	.hw_params	= mtk_afe_dais_hw_params,
 	.hw_free	= mtk_afe_dais_hw_free,
-	.prepare	= mtk_afe_dais_prepare,
 	.trigger	= mtk_afe_dais_trigger,
 };
 
@@ -1082,7 +1070,7 @@
 static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id)
 {
 	struct mtk_afe *afe = dev_id;
-	unsigned int reg_value, hw_ptr;
+	unsigned int reg_value;
 	int i, ret;
 
 	ret = regmap_read(afe->regmap, AFE_IRQ_STATUS, &reg_value);
@@ -1098,13 +1086,6 @@
 		if (!(reg_value & (1 << memif->data->irq_clr_shift)))
 			continue;
 
-		ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur,
-				  &hw_ptr);
-		if (ret || hw_ptr == 0) {
-			dev_err(afe->dev, "%s hw_ptr err\n", __func__);
-			hw_ptr = memif->phys_buf_addr;
-		}
-		memif->hw_ptr = hw_ptr - memif->phys_buf_addr;
 		snd_pcm_period_elapsed(memif->substream);
 	}
 
@@ -1119,6 +1100,9 @@
 {
 	struct mtk_afe *afe = dev_get_drvdata(dev);
 
+	/* disable AFE */
+	regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0);
+
 	/* disable AFE clk */
 	regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
 			   AUD_TCON0_PDN_AFE, AUD_TCON0_PDN_AFE);
@@ -1165,6 +1149,9 @@
 
 	/* unmask all IRQs */
 	regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN, 0xff, 0xff);
+
+	/* enable AFE */
+	regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1);
 	return 0;
 
 err_bck0:
diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c
index 584b237..f83cc2b 100644
--- a/sound/soc/omap/omap-hdmi-audio.c
+++ b/sound/soc/omap/omap-hdmi-audio.c
@@ -368,6 +368,8 @@
 	card->owner = THIS_MODULE;
 	card->dai_link =
 		devm_kzalloc(dev, sizeof(*(card->dai_link)), GFP_KERNEL);
+	if (!card->dai_link)
+		return -ENOMEM;
 	card->dai_link->name = card->name;
 	card->dai_link->stream_name = card->name;
 	card->dai_link->cpu_dai_name = dev_name(ad->dssdev);
diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c
index 6147e86..416ea64 100644
--- a/sound/soc/pxa/brownstone.c
+++ b/sound/soc/pxa/brownstone.c
@@ -63,8 +63,7 @@
 		sysclk    = params_rate(params) * 512;
 		sspa_mclk = params_rate(params) * 64;
 	}
-	sspa_div = freq_out;
-	do_div(sspa_div, sspa_mclk);
+	sspa_div = freq_out / sspa_mclk;
 
 	snd_soc_dai_set_sysclk(cpu_dai, MMP_SSPA_CLK_AUDIO, freq_out, 0);
 	snd_soc_dai_set_pll(cpu_dai, MMP_SYSCLK, 0, freq_out, sysclk);
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
index 29bc60e8..5c8f9db 100644
--- a/sound/soc/pxa/mioa701_wm9713.c
+++ b/sound/soc/pxa/mioa701_wm9713.c
@@ -81,8 +81,12 @@
 static int rear_amp_event(struct snd_soc_dapm_widget *widget,
 			  struct snd_kcontrol *kctl, int event)
 {
-	struct snd_soc_codec *codec = widget->dapm->card->rtd[0].codec;
+	struct snd_soc_card *card = widget->dapm->card;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_codec *codec;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+	codec = rtd->codec;
 	return rear_amp_power(codec, SND_SOC_DAPM_EVENT_ON(event));
 }
 
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index e5101e0..00b6c9d 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -355,6 +355,7 @@
 	.readable_reg = lpass_cpu_regmap_readable,
 	.volatile_reg = lpass_cpu_regmap_volatile,
 	.cache_type = REGCACHE_FLAT,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 58ee645..6561c4c 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -34,13 +34,7 @@
 
 	struct regmap *regmap;
 
-/*
- * Used to indicate the tx/rx status.
- * I2S controller hopes to start the tx and rx together,
- * also to stop them when they are both try to stop.
-*/
-	bool tx_start;
-	bool rx_start;
+	bool is_master_mode;
 };
 
 static int i2s_runtime_suspend(struct device *dev)
@@ -81,37 +75,29 @@
 				   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE);
 
 		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_TXS_START | I2S_XFER_RXS_START,
-				   I2S_XFER_TXS_START | I2S_XFER_RXS_START);
-
-		i2s->tx_start = true;
+				   I2S_XFER_TXS_START,
+				   I2S_XFER_TXS_START);
 	} else {
-		i2s->tx_start = false;
-
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
 
-		if (!i2s->rx_start) {
-			regmap_update_bits(i2s->regmap, I2S_XFER,
-					   I2S_XFER_TXS_START |
-					   I2S_XFER_RXS_START,
-					   I2S_XFER_TXS_STOP |
-					   I2S_XFER_RXS_STOP);
+		regmap_update_bits(i2s->regmap, I2S_XFER,
+				   I2S_XFER_TXS_START,
+				   I2S_XFER_TXS_STOP);
 
-			regmap_update_bits(i2s->regmap, I2S_CLR,
-					   I2S_CLR_TXC | I2S_CLR_RXC,
-					   I2S_CLR_TXC | I2S_CLR_RXC);
+		regmap_update_bits(i2s->regmap, I2S_CLR,
+				   I2S_CLR_TXC,
+				   I2S_CLR_TXC);
 
+		regmap_read(i2s->regmap, I2S_CLR, &val);
+
+		/* Should wait for clear operation to finish */
+		while (val & I2S_CLR_TXC) {
 			regmap_read(i2s->regmap, I2S_CLR, &val);
-
-			/* Should wait for clear operation to finish */
-			while (val) {
-				regmap_read(i2s->regmap, I2S_CLR, &val);
-				retry--;
-				if (!retry) {
-					dev_warn(i2s->dev, "fail to clear\n");
-					break;
-				}
+			retry--;
+			if (!retry) {
+				dev_warn(i2s->dev, "fail to clear\n");
+				break;
 			}
 		}
 	}
@@ -127,37 +113,29 @@
 				   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE);
 
 		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_TXS_START | I2S_XFER_RXS_START,
-				   I2S_XFER_TXS_START | I2S_XFER_RXS_START);
-
-		i2s->rx_start = true;
+				   I2S_XFER_RXS_START,
+				   I2S_XFER_RXS_START);
 	} else {
-		i2s->rx_start = false;
-
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
 
-		if (!i2s->tx_start) {
-			regmap_update_bits(i2s->regmap, I2S_XFER,
-					   I2S_XFER_TXS_START |
-					   I2S_XFER_RXS_START,
-					   I2S_XFER_TXS_STOP |
-					   I2S_XFER_RXS_STOP);
+		regmap_update_bits(i2s->regmap, I2S_XFER,
+				   I2S_XFER_RXS_START,
+				   I2S_XFER_RXS_STOP);
 
-			regmap_update_bits(i2s->regmap, I2S_CLR,
-					   I2S_CLR_TXC | I2S_CLR_RXC,
-					   I2S_CLR_TXC | I2S_CLR_RXC);
+		regmap_update_bits(i2s->regmap, I2S_CLR,
+				   I2S_CLR_RXC,
+				   I2S_CLR_RXC);
 
+		regmap_read(i2s->regmap, I2S_CLR, &val);
+
+		/* Should wait for clear operation to finish */
+		while (val & I2S_CLR_RXC) {
 			regmap_read(i2s->regmap, I2S_CLR, &val);
-
-			/* Should wait for clear operation to finish */
-			while (val) {
-				regmap_read(i2s->regmap, I2S_CLR, &val);
-				retry--;
-				if (!retry) {
-					dev_warn(i2s->dev, "fail to clear\n");
-					break;
-				}
+			retry--;
+			if (!retry) {
+				dev_warn(i2s->dev, "fail to clear\n");
+				break;
 			}
 		}
 	}
@@ -174,9 +152,11 @@
 	case SND_SOC_DAIFMT_CBS_CFS:
 		/* Set source clock in Master mode */
 		val = I2S_CKR_MSS_MASTER;
+		i2s->is_master_mode = true;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM:
 		val = I2S_CKR_MSS_SLAVE;
+		i2s->is_master_mode = false;
 		break;
 	default:
 		return -EINVAL;
@@ -228,6 +208,26 @@
 	struct rk_i2s_dev *i2s = to_info(dai);
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	unsigned int val = 0;
+	unsigned int mclk_rate, bclk_rate, div_bclk, div_lrck;
+
+	if (i2s->is_master_mode) {
+		mclk_rate = clk_get_rate(i2s->mclk);
+		bclk_rate = 2 * 32 * params_rate(params);
+		if (bclk_rate && mclk_rate % bclk_rate)
+			return -EINVAL;
+
+		div_bclk = mclk_rate / bclk_rate;
+		div_lrck = bclk_rate / params_rate(params);
+		regmap_update_bits(i2s->regmap, I2S_CKR,
+				   I2S_CKR_MDIV_MASK,
+				   I2S_CKR_MDIV(div_bclk));
+
+		regmap_update_bits(i2s->regmap, I2S_CKR,
+				   I2S_CKR_TSD_MASK |
+				   I2S_CKR_RSD_MASK,
+				   I2S_CKR_TSD(div_lrck) |
+				   I2S_CKR_RSD(div_lrck));
+	}
 
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S8:
@@ -242,6 +242,9 @@
 	case SNDRV_PCM_FORMAT_S24_LE:
 		val |= I2S_TXCR_VDW(24);
 		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		val |= I2S_TXCR_VDW(32);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -360,7 +363,8 @@
 		.formats = (SNDRV_PCM_FMTBIT_S8 |
 			    SNDRV_PCM_FMTBIT_S16_LE |
 			    SNDRV_PCM_FMTBIT_S20_3LE |
-			    SNDRV_PCM_FMTBIT_S24_LE),
+			    SNDRV_PCM_FMTBIT_S24_LE |
+			    SNDRV_PCM_FMTBIT_S32_LE),
 	},
 	.capture = {
 		.stream_name = "Capture",
@@ -370,7 +374,8 @@
 		.formats = (SNDRV_PCM_FMTBIT_S8 |
 			    SNDRV_PCM_FMTBIT_S16_LE |
 			    SNDRV_PCM_FMTBIT_S20_3LE |
-			    SNDRV_PCM_FMTBIT_S24_LE),
+			    SNDRV_PCM_FMTBIT_S24_LE |
+			    SNDRV_PCM_FMTBIT_S32_LE),
 	},
 	.ops = &rockchip_i2s_dai_ops,
 	.symmetric_rates = 1,
@@ -451,6 +456,7 @@
 {
 	struct device_node *node = pdev->dev.of_node;
 	struct rk_i2s_dev *i2s;
+	struct snd_soc_dai_driver *soc_dai;
 	struct resource *res;
 	void __iomem *regs;
 	int ret;
@@ -511,17 +517,26 @@
 			goto err_pm_disable;
 	}
 
-	/* refine capture channels */
+	soc_dai = devm_kzalloc(&pdev->dev,
+			       sizeof(*soc_dai), GFP_KERNEL);
+	if (!soc_dai)
+		return -ENOMEM;
+
+	memcpy(soc_dai, &rockchip_i2s_dai, sizeof(*soc_dai));
+	if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) {
+		if (val >= 2 && val <= 8)
+			soc_dai->playback.channels_max = val;
+	}
+
 	if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) {
 		if (val >= 2 && val <= 8)
-			rockchip_i2s_dai.capture.channels_max = val;
-		else
-			rockchip_i2s_dai.capture.channels_max = 2;
+			soc_dai->capture.channels_max = val;
 	}
 
 	ret = devm_snd_soc_register_component(&pdev->dev,
 					      &rockchip_i2s_component,
-					      &rockchip_i2s_dai, 1);
+					      soc_dai, 1);
+
 	if (ret) {
 		dev_err(&pdev->dev, "Could not register DAI\n");
 		goto err_suspend;
diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
index 26567b1..5436102 100644
--- a/sound/soc/rockchip/rockchip_max98090.c
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -80,11 +80,17 @@
 	switch (params_rate(params)) {
 	case 8000:
 	case 16000:
+	case 24000:
+	case 32000:
 	case 48000:
+	case 64000:
 	case 96000:
 		mclk = 12288000;
 		break;
+	case 11025:
+	case 22050:
 	case 44100:
+	case 88200:
 		mclk = 11289600;
 		break;
 	default:
diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c
index 68c62e4..440a802 100644
--- a/sound/soc/rockchip/rockchip_rt5645.c
+++ b/sound/soc/rockchip/rockchip_rt5645.c
@@ -79,11 +79,17 @@
 	switch (params_rate(params)) {
 	case 8000:
 	case 16000:
+	case 24000:
+	case 32000:
 	case 48000:
+	case 64000:
 	case 96000:
 		mclk = 12288000;
 		break;
+	case 11025:
+	case 22050:
 	case 44100:
+	case 88200:
 		mclk = 11289600;
 		break;
 	default:
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 3744c9e..78baa26 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -1,8 +1,6 @@
 config SND_SOC_SAMSUNG
 	tristate "ASoC support for Samsung"
 	depends on (PLAT_SAMSUNG || ARCH_EXYNOS)
-	depends on S3C64XX_PL080 || !ARCH_S3C64XX
-	depends on S3C24XX_DMAC || !ARCH_S3C24XX
 	select SND_SOC_GENERIC_DMAENGINE_PCM
 	help
 	  Say Y or M if you want to add support for codecs attached to
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
index e414550..4a7a503 100644
--- a/sound/soc/samsung/ac97.c
+++ b/sound/soc/samsung/ac97.c
@@ -324,7 +324,7 @@
 
 static int s3c_ac97_probe(struct platform_device *pdev)
 {
-	struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res;
+	struct resource *mem_res, *irq_res;
 	struct s3c_audio_pdata *ac97_pdata;
 	int ret;
 
@@ -335,24 +335,6 @@
 	}
 
 	/* Check for availability of necessary resource */
-	dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-	if (!dmatx_res) {
-		dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n");
-		return -ENXIO;
-	}
-
-	dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-	if (!dmarx_res) {
-		dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n");
-		return -ENXIO;
-	}
-
-	dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
-	if (!dmamic_res) {
-		dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n");
-		return -ENXIO;
-	}
-
 	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!irq_res) {
 		dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
@@ -364,11 +346,11 @@
 	if (IS_ERR(s3c_ac97.regs))
 		return PTR_ERR(s3c_ac97.regs);
 
-	s3c_ac97_pcm_out.channel = dmatx_res->start;
+	s3c_ac97_pcm_out.slave = ac97_pdata->dma_playback;
 	s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
-	s3c_ac97_pcm_in.channel = dmarx_res->start;
+	s3c_ac97_pcm_in.slave = ac97_pdata->dma_capture;
 	s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
-	s3c_ac97_mic_in.channel = dmamic_res->start;
+	s3c_ac97_mic_in.slave = ac97_pdata->dma_capture_mic;
 	s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA;
 
 	init_completion(&s3c_ac97.done);
@@ -406,7 +388,8 @@
 	if (ret)
 		goto err5;
 
-	ret = samsung_asoc_dma_platform_register(&pdev->dev);
+	ret = samsung_asoc_dma_platform_register(&pdev->dev,
+						 ac97_pdata->dma_filter);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
 		goto err5;
diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c
index e5f05e6..3dd246f 100644
--- a/sound/soc/samsung/bells.c
+++ b/sound/soc/samsung/bells.c
@@ -58,11 +58,16 @@
 				struct snd_soc_dapm_context *dapm,
 				enum snd_soc_bias_level level)
 {
-	struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *codec_dai;
+	struct snd_soc_codec *codec;
 	struct bells_drvdata *bells = card->drvdata;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
+	codec_dai = rtd->codec_dai;
+	codec = codec_dai->codec;
+
 	if (dapm->dev != codec_dai->dev)
 		return 0;
 
@@ -99,11 +104,16 @@
 				     struct snd_soc_dapm_context *dapm,
 				     enum snd_soc_bias_level level)
 {
-	struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
-	struct snd_soc_codec *codec = codec_dai->codec;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *codec_dai;
+	struct snd_soc_codec *codec;
 	struct bells_drvdata *bells = card->drvdata;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
+	codec_dai = rtd->codec_dai;
+	codec = codec_dai->codec;
+
 	if (dapm->dev != codec_dai->dev)
 		return 0;
 
@@ -137,14 +147,22 @@
 static int bells_late_probe(struct snd_soc_card *card)
 {
 	struct bells_drvdata *bells = card->drvdata;
-	struct snd_soc_codec *wm0010 = card->rtd[DAI_AP_DSP].codec;
-	struct snd_soc_codec *codec = card->rtd[DAI_DSP_CODEC].codec;
-	struct snd_soc_dai *aif1_dai = card->rtd[DAI_DSP_CODEC].codec_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_codec *wm0010;
+	struct snd_soc_codec *codec;
+	struct snd_soc_dai *aif1_dai;
 	struct snd_soc_dai *aif2_dai;
 	struct snd_soc_dai *aif3_dai;
 	struct snd_soc_dai *wm9081_dai;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_AP_DSP].name);
+	wm0010 = rtd->codec;
+
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name);
+	codec = rtd->codec;
+	aif1_dai = rtd->codec_dai;
+
 	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
 				       ARIZONA_CLK_SRC_FLL1,
 				       bells->sysclk_rate,
@@ -181,7 +199,8 @@
 		return ret;
 	}
 
-	aif2_dai = card->rtd[DAI_CODEC_CP].cpu_dai;
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_CP].name);
+	aif2_dai = rtd->cpu_dai;
 
 	ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
 	if (ret != 0) {
@@ -192,8 +211,9 @@
 	if (card->num_rtd == DAI_CODEC_SUB)
 		return 0;
 
-	aif3_dai = card->rtd[DAI_CODEC_SUB].cpu_dai;
-	wm9081_dai = card->rtd[DAI_CODEC_SUB].codec_dai;
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_SUB].name);
+	aif3_dai = rtd->cpu_dai;
+	wm9081_dai = rtd->codec_dai;
 
 	ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0);
 	if (ret != 0) {
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h
index 0e85dcf..a7616cc 100644
--- a/sound/soc/samsung/dma.h
+++ b/sound/soc/samsung/dma.h
@@ -13,9 +13,10 @@
 #define _S3C_AUDIO_H
 
 #include <sound/dmaengine_pcm.h>
+#include <linux/dmaengine.h>
 
 struct s3c_dma_params {
-	int channel;				/* Channel ID */
+	void *slave;				/* Channel ID */
 	dma_addr_t dma_addr;
 	int dma_size;			/* Size of the DMA transfer */
 	char *ch_name;
@@ -25,6 +26,7 @@
 void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
 				struct s3c_dma_params *playback,
 				struct s3c_dma_params *capture);
-int samsung_asoc_dma_platform_register(struct device *dev);
+int samsung_asoc_dma_platform_register(struct device *dev,
+				       dma_filter_fn fn);
 
 #endif
diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c
index 506f5bf..0631259 100644
--- a/sound/soc/samsung/dmaengine.c
+++ b/sound/soc/samsung/dmaengine.c
@@ -28,17 +28,8 @@
 
 #include "dma.h"
 
-#ifdef CONFIG_ARCH_S3C64XX
-#define filter_fn pl08x_filter_id
-#elif defined(CONFIG_ARCH_S3C24XX)
-#define filter_fn s3c24xx_dma_filter
-#else
-#define filter_fn NULL
-#endif
-
-static const struct snd_dmaengine_pcm_config samsung_dmaengine_pcm_config = {
+static struct snd_dmaengine_pcm_config samsung_dmaengine_pcm_config = {
 	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
-	.compat_filter_fn = filter_fn,
 };
 
 void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
@@ -50,14 +41,14 @@
 
 	if (playback) {
 		playback_data = &playback->dma_data;
-		playback_data->filter_data = (void *)playback->channel;
+		playback_data->filter_data = playback->slave;
 		playback_data->chan_name = playback->ch_name;
 		playback_data->addr = playback->dma_addr;
 		playback_data->addr_width = playback->dma_size;
 	}
 	if (capture) {
 		capture_data = &capture->dma_data;
-		capture_data->filter_data = (void *)capture->channel;
+		capture_data->filter_data = capture->slave;
 		capture_data->chan_name = capture->ch_name;
 		capture_data->addr = capture->dma_addr;
 		capture_data->addr_width = capture->dma_size;
@@ -67,8 +58,11 @@
 }
 EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data);
 
-int samsung_asoc_dma_platform_register(struct device *dev)
+int samsung_asoc_dma_platform_register(struct device *dev,
+				       dma_filter_fn filter)
 {
+	samsung_dmaengine_pcm_config.compat_filter_fn = filter;
+
 	return devm_snd_dmaengine_pcm_register(dev,
 			&samsung_dmaengine_pcm_config,
 			SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME |
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index ea4ab37..84d9e77 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -89,6 +89,7 @@
 	struct s3c_dma_params dma_playback;
 	struct s3c_dma_params dma_capture;
 	struct s3c_dma_params idma_playback;
+	dma_filter_fn filter;
 	u32	quirks;
 	u32	suspend_i2smod;
 	u32	suspend_i2scon;
@@ -1244,7 +1245,8 @@
 		if (ret != 0)
 			return ret;
 
-		return samsung_asoc_dma_platform_register(&pdev->dev);
+		return samsung_asoc_dma_platform_register(&pdev->dev,
+							  sec_dai->filter);
 	}
 
 	pri_dai = i2s_alloc_dai(pdev, false);
@@ -1257,27 +1259,15 @@
 	pri_dai->lock = &pri_dai->spinlock;
 
 	if (!np) {
-		res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-		if (!res) {
-			dev_err(&pdev->dev,
-				"Unable to get I2S-TX dma resource\n");
-			return -ENXIO;
-		}
-		pri_dai->dma_playback.channel = res->start;
-
-		res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-		if (!res) {
-			dev_err(&pdev->dev,
-				"Unable to get I2S-RX dma resource\n");
-			return -ENXIO;
-		}
-		pri_dai->dma_capture.channel = res->start;
-
 		if (i2s_pdata == NULL) {
 			dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n");
 			return -EINVAL;
 		}
 
+		pri_dai->dma_playback.slave = i2s_pdata->dma_playback;
+		pri_dai->dma_capture.slave = i2s_pdata->dma_capture;
+		pri_dai->filter = i2s_pdata->dma_filter;
+
 		if (&i2s_pdata->type)
 			i2s_cfg = &i2s_pdata->type.i2s;
 
@@ -1339,9 +1329,8 @@
 		sec_dai->dma_playback.ch_name = "tx-sec";
 
 		if (!np) {
-			res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
-			if (res)
-				sec_dai->dma_playback.channel = res->start;
+			sec_dai->dma_playback.slave = i2s_pdata->dma_play_sec;
+			sec_dai->filter = i2s_pdata->dma_filter;
 		}
 
 		sec_dai->dma_playback.dma_size = 4;
@@ -1364,7 +1353,7 @@
 
 	pm_runtime_enable(&pdev->dev);
 
-	ret = samsung_asoc_dma_platform_register(&pdev->dev);
+	ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter);
 	if (ret != 0)
 		return ret;
 
diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c
index 31a820e..7cb204e 100644
--- a/sound/soc/samsung/littlemill.c
+++ b/sound/soc/samsung/littlemill.c
@@ -23,9 +23,13 @@
 					  struct snd_soc_dapm_context *dapm,
 					  enum snd_soc_bias_level level)
 {
-	struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *aif1_dai;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+	aif1_dai = rtd->codec_dai;
+
 	if (dapm->dev != aif1_dai->dev)
 		return 0;
 
@@ -66,9 +70,13 @@
 					       struct snd_soc_dapm_context *dapm,
 					       enum snd_soc_bias_level level)
 {
-	struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *aif1_dai;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+	aif1_dai = rtd->codec_dai;
+
 	if (dapm->dev != aif1_dai->dev)
 		return 0;
 
@@ -168,9 +176,13 @@
 		    struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_card *card = w->dapm->card;
-	struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *aif2_dai;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+	aif2_dai = rtd->cpu_dai;
+
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		ret = snd_soc_dai_set_pll(aif2_dai, WM8994_FLL2,
@@ -245,11 +257,19 @@
 
 static int littlemill_late_probe(struct snd_soc_card *card)
 {
-	struct snd_soc_codec *codec = card->rtd[0].codec;
-	struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
-	struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_codec *codec;
+	struct snd_soc_dai *aif1_dai;
+	struct snd_soc_dai *aif2_dai;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+	codec = rtd->codec;
+	aif1_dai = rtd->codec_dai;
+
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+	aif2_dai = rtd->cpu_dai;
+
 	ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
 				     32768, SND_SOC_CLOCK_IN);
 	if (ret < 0)
diff --git a/sound/soc/samsung/odroidx2_max98090.c b/sound/soc/samsung/odroidx2_max98090.c
index 596f118..0421727 100644
--- a/sound/soc/samsung/odroidx2_max98090.c
+++ b/sound/soc/samsung/odroidx2_max98090.c
@@ -25,10 +25,15 @@
 
 static int odroidx2_late_probe(struct snd_soc_card *card)
 {
-	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
-	struct snd_soc_dai *cpu_dai = card->rtd[0].cpu_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *codec_dai;
+	struct snd_soc_dai *cpu_dai;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+	codec_dai = rtd->codec_dai;
+	cpu_dai = rtd->cpu_dai;
+
 	ret = snd_soc_dai_set_sysclk(codec_dai, 0, MAX98090_MCLK,
 						SND_SOC_CLOCK_IN);
 
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index b320a9d..498f563 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -486,8 +486,9 @@
 static int s3c_pcm_dev_probe(struct platform_device *pdev)
 {
 	struct s3c_pcm_info *pcm;
-	struct resource *mem_res, *dmatx_res, *dmarx_res;
+	struct resource *mem_res;
 	struct s3c_audio_pdata *pcm_pdata;
+	dma_filter_fn filter;
 	int ret;
 
 	/* Check for valid device index */
@@ -499,18 +500,6 @@
 	pcm_pdata = pdev->dev.platform_data;
 
 	/* Check for availability of necessary resource */
-	dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-	if (!dmatx_res) {
-		dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n");
-		return -ENXIO;
-	}
-
-	dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-	if (!dmarx_res) {
-		dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n");
-		return -ENXIO;
-	}
-
 	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!mem_res) {
 		dev_err(&pdev->dev, "Unable to get register resource\n");
@@ -568,8 +557,12 @@
 	s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
 							+ S3C_PCM_TXFIFO;
 
-	s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start;
-	s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start;
+	filter = NULL;
+	if (pcm_pdata) {
+		s3c_pcm_stereo_in[pdev->id].slave = pcm_pdata->dma_capture;
+		s3c_pcm_stereo_out[pdev->id].slave = pcm_pdata->dma_playback;
+		filter = pcm_pdata->dma_filter;
+	}
 
 	pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
 	pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
@@ -583,7 +576,7 @@
 		goto err5;
 	}
 
-	ret = samsung_asoc_dma_platform_register(&pdev->dev);
+	ret = samsung_asoc_dma_platform_register(&pdev->dev, filter);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
 		goto err5;
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
index 2b766d2..204029d 100644
--- a/sound/soc/samsung/s3c2412-i2s.c
+++ b/sound/soc/samsung/s3c2412-i2s.c
@@ -25,7 +25,6 @@
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
 
-#include <mach/dma.h>
 #include <mach/gpio-samsung.h>
 #include <plat/gpio-cfg.h>
 
@@ -33,14 +32,14 @@
 #include "regs-i2s-v2.h"
 #include "s3c2412-i2s.h"
 
+#include <linux/platform_data/asoc-s3c.h>
+
 static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = {
-	.channel	= DMACH_I2S_OUT,
 	.ch_name	= "tx",
 	.dma_size	= 4,
 };
 
 static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
-	.channel	= DMACH_I2S_IN,
 	.ch_name	= "rx",
 	.dma_size	= 4,
 };
@@ -152,6 +151,12 @@
 {
 	int ret = 0;
 	struct resource *res;
+	struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev);
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "missing platform data");
+		return -ENXIO;
+	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	s3c2412_i2s.regs = devm_ioremap_resource(&pdev->dev, res);
@@ -159,7 +164,9 @@
 		return PTR_ERR(s3c2412_i2s.regs);
 
 	s3c2412_i2s_pcm_stereo_out.dma_addr = res->start + S3C2412_IISTXD;
+	s3c2412_i2s_pcm_stereo_out.slave = pdata->dma_playback;
 	s3c2412_i2s_pcm_stereo_in.dma_addr = res->start + S3C2412_IISRXD;
+	s3c2412_i2s_pcm_stereo_in.slave = pdata->dma_capture;
 
 	ret = s3c_i2sv2_register_component(&pdev->dev, -1,
 					   &s3c2412_i2s_component,
@@ -169,7 +176,8 @@
 		return ret;
 	}
 
-	ret = samsung_asoc_dma_platform_register(&pdev->dev);
+	ret = samsung_asoc_dma_platform_register(&pdev->dev,
+						 pdata->dma_filter);
 	if (ret)
 		pr_err("failed to register the DMA: %d\n", ret);
 
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
index 5bf7236..b3a475d 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -23,7 +23,6 @@
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
 
-#include <mach/dma.h>
 #include <mach/gpio-samsung.h>
 #include <plat/gpio-cfg.h>
 #include "regs-iis.h"
@@ -31,14 +30,14 @@
 #include "dma.h"
 #include "s3c24xx-i2s.h"
 
+#include <linux/platform_data/asoc-s3c.h>
+
 static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = {
-	.channel	= DMACH_I2S_OUT,
 	.ch_name	= "tx",
 	.dma_size	= 2,
 };
 
 static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = {
-	.channel	= DMACH_I2S_IN,
 	.ch_name	= "rx",
 	.dma_size	= 2,
 };
@@ -454,6 +453,12 @@
 {
 	int ret = 0;
 	struct resource *res;
+	struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev);
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "missing platform data");
+		return -ENXIO;
+	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
@@ -465,7 +470,9 @@
 		return PTR_ERR(s3c24xx_i2s.regs);
 
 	s3c24xx_i2s_pcm_stereo_out.dma_addr = res->start + S3C2410_IISFIFO;
+	s3c24xx_i2s_pcm_stereo_out.slave = pdata->dma_playback;
 	s3c24xx_i2s_pcm_stereo_in.dma_addr = res->start + S3C2410_IISFIFO;
+	s3c24xx_i2s_pcm_stereo_in.slave = pdata->dma_capture;
 
 	ret = devm_snd_soc_register_component(&pdev->dev,
 			&s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1);
@@ -474,7 +481,8 @@
 		return ret;
 	}
 
-	ret = samsung_asoc_dma_platform_register(&pdev->dev);
+	ret = samsung_asoc_dma_platform_register(&pdev->dev,
+						 pdata->dma_filter);
 	if (ret)
 		pr_err("failed to register the dma: %d\n", ret);
 
diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c
index 07ce2cf..d8ac907 100644
--- a/sound/soc/samsung/snow.c
+++ b/sound/soc/samsung/snow.c
@@ -35,10 +35,15 @@
 
 static int snow_late_probe(struct snd_soc_card *card)
 {
-	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
-	struct snd_soc_dai *cpu_dai = card->rtd[0].cpu_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *codec_dai;
+	struct snd_soc_dai *cpu_dai;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+	codec_dai = rtd->codec_dai;
+	cpu_dai = rtd->cpu_dai;
+
 	/* Set the MCLK rate for the codec */
 	ret = snd_soc_dai_set_sysclk(codec_dai, 0,
 					FIN_PLL_RATE, SND_SOC_CLOCK_IN);
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index 36dbc0e9..4687f52 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -359,20 +359,15 @@
 static int spdif_probe(struct platform_device *pdev)
 {
 	struct s3c_audio_pdata *spdif_pdata;
-	struct resource *mem_res, *dma_res;
+	struct resource *mem_res;
 	struct samsung_spdif_info *spdif;
+	dma_filter_fn filter;
 	int ret;
 
 	spdif_pdata = pdev->dev.platform_data;
 
 	dev_dbg(&pdev->dev, "Entered %s\n", __func__);
 
-	dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-	if (!dma_res) {
-		dev_err(&pdev->dev, "Unable to get dma resource.\n");
-		return -ENXIO;
-	}
-
 	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!mem_res) {
 		dev_err(&pdev->dev, "Unable to get register resource.\n");
@@ -432,11 +427,15 @@
 
 	spdif_stereo_out.dma_size = 2;
 	spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
-	spdif_stereo_out.channel = dma_res->start;
+	filter = NULL;
+	if (spdif_pdata) {
+		spdif_stereo_out.slave = spdif_pdata->dma_playback;
+		filter = spdif_pdata->dma_filter;
+	}
 
 	spdif->dma_playback = &spdif_stereo_out;
 
-	ret = samsung_asoc_dma_platform_register(&pdev->dev);
+	ret = samsung_asoc_dma_platform_register(&pdev->dev, filter);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register DMA: %d\n", ret);
 		goto err4;
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index d1ae21c5..083ef5e 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -25,9 +25,13 @@
 				   struct snd_soc_dapm_context *dapm,
 				   enum snd_soc_bias_level level)
 {
-	struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *codec_dai;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+	codec_dai = rtd->codec_dai;
+
 	if (dapm->dev != codec_dai->dev)
 		return 0;
 
@@ -57,9 +61,13 @@
 					struct snd_soc_dapm_context *dapm,
 					enum snd_soc_bias_level level)
 {
-	struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *codec_dai;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
+	codec_dai = rtd->codec_dai;
+
 	if (dapm->dev != codec_dai->dev)
 		return 0;
 
diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c
index 85ccfb7..3310eda 100644
--- a/sound/soc/samsung/tobermory.c
+++ b/sound/soc/samsung/tobermory.c
@@ -23,9 +23,13 @@
 					  struct snd_soc_dapm_context *dapm,
 					  enum snd_soc_bias_level level)
 {
-	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *codec_dai;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+	codec_dai = rtd->codec_dai;
+
 	if (dapm->dev != codec_dai->dev)
 		return 0;
 
@@ -62,9 +66,13 @@
 					       struct snd_soc_dapm_context *dapm,
 					       enum snd_soc_bias_level level)
 {
-	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *codec_dai;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+	codec_dai = rtd->codec_dai;
+
 	if (dapm->dev != codec_dai->dev)
 		return 0;
 
@@ -170,10 +178,15 @@
 
 static int tobermory_late_probe(struct snd_soc_card *card)
 {
-	struct snd_soc_codec *codec = card->rtd[0].codec;
-	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_codec *codec;
+	struct snd_soc_dai *codec_dai;
 	int ret;
 
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+	codec = rtd->codec;
+	codec_dai = rtd->codec_dai;
+
 	ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
 				     32768, SND_SOC_CLOCK_IN);
 	if (ret < 0)
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 206d1ed..c9902a6 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -36,7 +36,6 @@
 
 config SND_SOC_RCAR
 	tristate "R-Car series SRU/SCU/SSIU/SSI support"
-	depends on DMA_OF
 	depends on COMMON_CLK
 	select SND_SIMPLE_CARD
 	select REGMAP_MMIO
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 0215c78..ead5201 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1362,15 +1362,18 @@
 
 static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev)
 {
-	dma_cap_mask_t mask;
 	int is_play = fsi_stream_is_play(fsi, io);
 
+#ifdef CONFIG_SUPERH
+	dma_cap_mask_t mask;
 	dma_cap_zero(mask);
 	dma_cap_set(DMA_SLAVE, mask);
 
-	io->chan = dma_request_slave_channel_compat(mask,
-				shdma_chan_filter, (void *)io->dma_id,
-				dev, is_play ? "tx" : "rx");
+	io->chan = dma_request_channel(mask, shdma_chan_filter,
+				       (void *)io->dma_id);
+#else
+	io->chan = dma_request_slave_channel(dev, is_play ? "tx" : "rx");
+#endif
 	if (io->chan) {
 		struct dma_slave_config cfg = {};
 		int ret;
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
index 8b25850..a89ddf7 100644
--- a/sound/soc/sh/rcar/Makefile
+++ b/sound/soc/sh/rcar/Makefile
@@ -1,4 +1,4 @@
-snd-soc-rcar-objs	:= core.o gen.o dma.o adg.o ssi.o src.o ctu.o mix.o dvc.o
+snd-soc-rcar-objs	:= core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o
 obj-$(CONFIG_SND_SOC_RCAR)	+= snd-soc-rcar.o
 
 snd-soc-rsrc-card-objs	:= rsrc-card.o
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 2a5b3a2..6d3ef36 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -68,8 +68,8 @@
 
 static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
 {
-	struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
-	int id = rsnd_mod_id(mod);
+	struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+	int id = rsnd_mod_id(ssi_mod);
 	int ws = id;
 
 	if (rsnd_ssi_is_pin_sharing(io)) {
@@ -90,13 +90,13 @@
 	return (0x6 + ws) << 8;
 }
 
-int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
+int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
 				 struct rsnd_dai_stream *io)
 {
-	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod);
 	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
 	struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
-	int id = rsnd_mod_id(mod);
+	int id = rsnd_mod_id(cmd_mod);
 	int shift = (id % 2) ? 16 : 0;
 	u32 mask, val;
 
@@ -242,68 +242,6 @@
 	return rsnd_adg_set_src_timsel_gen2(src_mod, io, val);
 }
 
-int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
-				  struct rsnd_mod *mod,
-				  unsigned int src_rate,
-				  unsigned int dst_rate)
-{
-	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
-	struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
-	struct device *dev = rsnd_priv_to_dev(priv);
-	int idx, sel, div, shift;
-	u32 mask, val;
-	int id = rsnd_mod_id(mod);
-	unsigned int sel_rate [] = {
-		clk_get_rate(adg->clk[CLKA]),	/* 000: CLKA */
-		clk_get_rate(adg->clk[CLKB]),	/* 001: CLKB */
-		clk_get_rate(adg->clk[CLKC]),	/* 010: CLKC */
-		0,				/* 011: MLBCLK (not used) */
-		adg->rbga_rate_for_441khz,	/* 100: RBGA */
-		adg->rbgb_rate_for_48khz,	/* 101: RBGB */
-	};
-
-	/* find div (= 1/128, 1/256, 1/512, 1/1024, 1/2048 */
-	for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
-		for (div  = 128,	idx = 0;
-		     div <= 2048;
-		     div *= 2,		idx++) {
-			if (src_rate == sel_rate[sel] / div) {
-				val = (idx << 4) | sel;
-				goto find_rate;
-			}
-		}
-	}
-	dev_err(dev, "can't find convert src clk\n");
-	return -EINVAL;
-
-find_rate:
-	shift	= (id % 4) * 8;
-	mask	= 0xFF << shift;
-	val	= val << shift;
-
-	dev_dbg(dev, "adg convert src clk = %02x\n", val);
-
-	switch (id / 4) {
-	case 0:
-		rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL3, mask, val);
-		break;
-	case 1:
-		rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL4, mask, val);
-		break;
-	case 2:
-		rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL5, mask, val);
-		break;
-	}
-
-	/*
-	 * Gen1 doesn't need dst_rate settings,
-	 * since it uses SSI WS pin.
-	 * see also rsnd_src_set_route_if_gen1()
-	 */
-
-	return 0;
-}
-
 static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
 {
 	struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
@@ -337,20 +275,16 @@
 	}
 }
 
-int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod)
+int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod)
 {
-	/*
-	 * "mod" = "ssi" here.
-	 * we can get "ssi id" from mod
-	 */
-	rsnd_adg_set_ssi_clk(mod, 0);
+	rsnd_adg_set_ssi_clk(ssi_mod, 0);
 
 	return 0;
 }
 
-int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
+int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
 {
-	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
 	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct clk *clk;
@@ -394,14 +328,10 @@
 
 found_clock:
 
-	/*
-	 * This "mod" = "ssi" here.
-	 * we can get "ssi id" from mod
-	 */
-	rsnd_adg_set_ssi_clk(mod, data);
+	rsnd_adg_set_ssi_clk(ssi_mod, data);
 
 	dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n",
-		rsnd_mod_name(mod), rsnd_mod_id(mod),
+		rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod),
 		data, rate);
 
 	return 0;
@@ -418,15 +348,20 @@
 		[CLKC]	= "clk_c",
 		[CLKI]	= "clk_i",
 	};
-	int i;
+	int i, ret;
 
 	for (i = 0; i < CLKMAX; i++) {
 		clk = devm_clk_get(dev, clk_name[i]);
 		adg->clk[i] = IS_ERR(clk) ? NULL : clk;
 	}
 
-	for_each_rsnd_clk(clk, adg, i)
+	for_each_rsnd_clk(clk, adg, i) {
+		ret = clk_prepare_enable(clk);
+		if (ret < 0)
+			dev_warn(dev, "can't use clk %d\n", i);
+
 		dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
+	}
 }
 
 static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
@@ -437,7 +372,7 @@
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct device_node *np = dev->of_node;
 	u32 ckr, rbgx, rbga, rbgb;
-	u32 rate, req_rate, div;
+	u32 rate, req_rate = 0, div;
 	uint32_t count = 0;
 	unsigned long req_48kHz_rate, req_441kHz_rate;
 	int i;
@@ -572,9 +507,7 @@
 		ckr, rbga, rbgb);
 }
 
-int rsnd_adg_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv)
+int rsnd_adg_probe(struct rsnd_priv *priv)
 {
 	struct rsnd_adg *adg;
 	struct device *dev = rsnd_priv_to_dev(priv);
@@ -600,3 +533,14 @@
 
 	return 0;
 }
+
+void rsnd_adg_remove(struct rsnd_priv *priv)
+{
+	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+	struct clk *clk;
+	int i;
+
+	for_each_rsnd_clk(clk, adg, i) {
+		clk_disable_unprepare(clk);
+	}
+}
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c
new file mode 100644
index 0000000..cd1f064
--- /dev/null
+++ b/sound/soc/sh/rcar/cmd.c
@@ -0,0 +1,171 @@
+/*
+ * Renesas R-Car CMD support
+ *
+ * Copyright (C) 2015 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 "rsnd.h"
+
+struct rsnd_cmd {
+	struct rsnd_mod mod;
+};
+
+#define CMD_NAME "cmd"
+
+#define rsnd_cmd_nr(priv) ((priv)->cmd_nr)
+#define for_each_rsnd_cmd(pos, priv, i)					\
+	for ((i) = 0;							\
+	     ((i) < rsnd_cmd_nr(priv)) &&				\
+		     ((pos) = (struct rsnd_cmd *)(priv)->cmd + i);	\
+	     i++)
+
+static int rsnd_cmd_init(struct rsnd_mod *mod,
+			 struct rsnd_dai_stream *io,
+			 struct rsnd_priv *priv)
+{
+	struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
+	struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
+	struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	u32 data;
+
+	if (!mix && !dvc)
+		return 0;
+
+	if (mix) {
+		struct rsnd_dai *rdai;
+		int i;
+		u32 path[] = {
+			[0] = 0,
+			[1] = 1 << 0,
+			[2] = 0,
+			[3] = 0,
+			[4] = 0,
+			[5] = 1 << 8
+		};
+
+		/*
+		 * it is assuming that integrater is well understanding about
+		 * data path. Here doesn't check impossible connection,
+		 * like src2 + src5
+		 */
+		data = 0;
+		for_each_rsnd_dai(rdai, priv, i) {
+			io = &rdai->playback;
+			if (mix == rsnd_io_to_mod_mix(io))
+				data |= path[rsnd_mod_id(src)];
+
+			io = &rdai->capture;
+			if (mix == rsnd_io_to_mod_mix(io))
+				data |= path[rsnd_mod_id(src)];
+		}
+
+	} else {
+		u32 path[] = {
+			[0] = 0x30000,
+			[1] = 0x30001,
+			[2] = 0x40000,
+			[3] = 0x10000,
+			[4] = 0x20000,
+			[5] = 0x40100
+		};
+
+		data = path[rsnd_mod_id(src)];
+	}
+
+	dev_dbg(dev, "ctu/mix path = 0x%08x", data);
+
+	rsnd_mod_write(mod, CMD_ROUTE_SLCT, data);
+	rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
+
+	rsnd_adg_set_cmd_timsel_gen2(mod, io);
+
+	return 0;
+}
+
+static int rsnd_cmd_start(struct rsnd_mod *mod,
+			  struct rsnd_dai_stream *io,
+			  struct rsnd_priv *priv)
+{
+	rsnd_mod_write(mod, CMD_CTRL, 0x10);
+
+	return 0;
+}
+
+static int rsnd_cmd_stop(struct rsnd_mod *mod,
+			 struct rsnd_dai_stream *io,
+			 struct rsnd_priv *priv)
+{
+	rsnd_mod_write(mod, CMD_CTRL, 0);
+
+	return 0;
+}
+
+static struct rsnd_mod_ops rsnd_cmd_ops = {
+	.name	= CMD_NAME,
+	.init	= rsnd_cmd_init,
+	.start	= rsnd_cmd_start,
+	.stop	= rsnd_cmd_stop,
+};
+
+int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id)
+{
+	struct rsnd_priv *priv = rsnd_io_to_priv(io);
+	struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id);
+
+	return rsnd_dai_connect(mod, io, mod->type);
+}
+
+struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
+{
+	if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv)))
+		id = 0;
+
+	return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id);
+}
+
+int rsnd_cmd_probe(struct rsnd_priv *priv)
+{
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct rsnd_cmd *cmd;
+	int i, nr, ret;
+
+	/* This driver doesn't support Gen1 at this point */
+	if (rsnd_is_gen1(priv))
+		return 0;
+
+	/* same number as DVC */
+	nr = priv->dvc_nr;
+	if (!nr)
+		return 0;
+
+	cmd = devm_kzalloc(dev, sizeof(*cmd) * nr, GFP_KERNEL);
+	if (!cmd)
+		return -ENOMEM;
+
+	priv->cmd_nr	= nr;
+	priv->cmd	= cmd;
+
+	for_each_rsnd_cmd(cmd, priv, i) {
+		ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
+				    &rsnd_cmd_ops, NULL, RSND_MOD_CMD, i);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+void rsnd_cmd_remove(struct rsnd_priv *priv)
+{
+	struct rsnd_cmd *cmd;
+	int i;
+
+	for_each_rsnd_cmd(cmd, priv, i) {
+		rsnd_mod_quit(rsnd_mod_get(cmd));
+	}
+}
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index deed48e..02b4b08 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -99,34 +99,17 @@
 #define RSND_RATES SNDRV_PCM_RATE_8000_96000
 #define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
 
-static const struct rsnd_of_data rsnd_of_data_gen1 = {
-	.flags = RSND_GEN1,
-};
-
-static const struct rsnd_of_data rsnd_of_data_gen2 = {
-	.flags = RSND_GEN2,
-};
-
 static const struct of_device_id rsnd_of_match[] = {
-	{ .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 },
-	{ .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 },
-	{ .compatible = "renesas,rcar_sound-gen3", .data = &rsnd_of_data_gen2 }, /* gen2 compatible */
+	{ .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 },
+	{ .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 },
+	{ .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN2 }, /* gen2 compatible */
 	{},
 };
 MODULE_DEVICE_TABLE(of, rsnd_of_match);
 
 /*
- *	rsnd_platform functions
+ *	rsnd_mod functions
  */
-#define rsnd_platform_call(priv, dai, func, param...)	\
-	(!(priv->info->func) ? 0 :		\
-	 priv->info->func(param))
-
-#define rsnd_is_enable_path(io, name) \
-	((io)->info ? (io)->info->name : NULL)
-#define rsnd_info_id(priv, io, name) \
-	((io)->info->name - priv->info->name##_info)
-
 void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
 {
 	if (mod->type != type) {
@@ -138,9 +121,6 @@
 	}
 }
 
-/*
- *	rsnd_mod functions
- */
 char *rsnd_mod_name(struct rsnd_mod *mod)
 {
 	if (!mod || !mod->ops)
@@ -192,19 +172,16 @@
 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
 	struct rsnd_dai_stream *io;
 	struct rsnd_dai *rdai;
-	int i, j;
+	int i;
 
-	for_each_rsnd_dai(rdai, priv, j) {
+	for_each_rsnd_dai(rdai, priv, i) {
+		io = &rdai->playback;
+		if (mod == io->mod[mod->type])
+			callback(mod, io);
 
-		for (i = 0; i < RSND_MOD_MAX; i++) {
-			io = &rdai->playback;
-			if (mod == io->mod[i])
-				callback(mod, io);
-
-			io = &rdai->capture;
-			if (mod == io->mod[i])
-				callback(mod, io);
-		}
+		io = &rdai->capture;
+		if (mod == io->mod[mod->type])
+			callback(mod, io);
 	}
 }
 
@@ -214,6 +191,43 @@
 	return !!io->substream;
 }
 
+void rsnd_set_slot(struct rsnd_dai *rdai,
+		   int slots, int num)
+{
+	rdai->slots	= slots;
+	rdai->slots_num	= num;
+}
+
+int rsnd_get_slot(struct rsnd_dai_stream *io)
+{
+	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+
+	return rdai->slots;
+}
+
+int rsnd_get_slot_num(struct rsnd_dai_stream *io)
+{
+	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+
+	return rdai->slots_num;
+}
+
+int rsnd_get_slot_width(struct rsnd_dai_stream *io)
+{
+	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+	int chan = runtime->channels;
+
+	/* Multi channel Mode */
+	if (rsnd_ssi_multi_slaves(io))
+		chan /= rsnd_get_slot_num(io);
+
+	/* TDM Extend Mode needs 8ch */
+	if (chan == 6)
+		chan = 8;
+
+	return chan;
+}
+
 /*
  *	ADINR function
  */
@@ -222,21 +236,17 @@
 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
 	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
 	struct device *dev = rsnd_priv_to_dev(priv);
-	u32 adinr = runtime->channels;
 
 	switch (runtime->sample_bits) {
 	case 16:
-		adinr |= (8 << 16);
-		break;
+		return 8 << 16;
 	case 32:
-		adinr |= (0 << 16);
-		break;
-	default:
-		dev_warn(dev, "not supported sample bits\n");
-		return 0;
+		return 0 << 16;
 	}
 
-	return adinr;
+	dev_warn(dev, "not supported sample bits\n");
+
+	return 0;
 }
 
 u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
@@ -267,13 +277,22 @@
  */
 u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
 {
-	struct rsnd_mod *src = rsnd_io_to_mod_src(io);
 	struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
-	struct rsnd_mod *target = src ? src : ssi;
+	struct rsnd_mod *target;
 	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
 	u32 val = 0x76543210;
 	u32 mask = ~0;
 
+	if (rsnd_io_is_play(io)) {
+		struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+
+		target = src ? src : ssi;
+	} else {
+		struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io);
+
+		target = cmd ? cmd : ssi;
+	}
+
 	mask <<= runtime->channels * 4;
 	val = val & mask;
 
@@ -300,20 +319,22 @@
 /*
  *	rsnd_dai functions
  */
-#define rsnd_mod_call(mod, io, func, param...)			\
+#define rsnd_mod_call(idx, io, func, param...)			\
 ({								\
 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);		\
+	struct rsnd_mod *mod = (io)->mod[idx];			\
 	struct device *dev = rsnd_priv_to_dev(priv);		\
+	u32 *status = (io)->mod_status + idx;			\
 	u32 mask = 0xF << __rsnd_mod_shift_##func;			\
-	u8 val  = (mod->status >> __rsnd_mod_shift_##func) & 0xF;	\
+	u8 val  = (*status >> __rsnd_mod_shift_##func) & 0xF;		\
 	u8 add  = ((val + __rsnd_mod_add_##func) & 0xF);		\
 	int ret = 0;							\
 	int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func;	\
-	mod->status = (mod->status & ~mask) +				\
+	*status = (*status & ~mask) +					\
 		(add << __rsnd_mod_shift_##func);			\
 	dev_dbg(dev, "%s[%d]\t0x%08x %s\n",				\
 		rsnd_mod_name(mod), rsnd_mod_id(mod),			\
-		mod->status, call ? #func : "");			\
+		*status, call ? #func : "");				\
 	if (call)							\
 		ret = (mod)->ops->func(mod, io, param);			\
 	ret;								\
@@ -327,13 +348,14 @@
 		mod = (io)->mod[i];				\
 		if (!mod)					\
 			continue;				\
-		ret |= rsnd_mod_call(mod, io, fn, param);	\
+		ret |= rsnd_mod_call(i, io, fn, param);		\
 	}							\
 	ret;							\
 })
 
-static int rsnd_dai_connect(struct rsnd_mod *mod,
-			    struct rsnd_dai_stream *io)
+int rsnd_dai_connect(struct rsnd_mod *mod,
+		     struct rsnd_dai_stream *io,
+		     enum rsnd_mod_type type)
 {
 	struct rsnd_priv *priv;
 	struct device *dev;
@@ -341,10 +363,13 @@
 	if (!mod)
 		return -EIO;
 
+	if (io->mod[type])
+		return -EINVAL;
+
 	priv = rsnd_mod_to_priv(mod);
 	dev = rsnd_priv_to_dev(priv);
 
-	io->mod[mod->type] = mod;
+	io->mod[type] = mod;
 
 	dev_dbg(dev, "%s[%d] is connected to io (%s)\n",
 		rsnd_mod_name(mod), rsnd_mod_id(mod),
@@ -354,9 +379,10 @@
 }
 
 static void rsnd_dai_disconnect(struct rsnd_mod *mod,
-				struct rsnd_dai_stream *io)
+				struct rsnd_dai_stream *io,
+				enum rsnd_mod_type type)
 {
-	io->mod[mod->type] = NULL;
+	io->mod[type] = NULL;
 }
 
 struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
@@ -469,7 +495,6 @@
 	struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
 	struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
 	struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
-	int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io));
 	int ret;
 	unsigned long flags;
 
@@ -479,10 +504,6 @@
 	case SNDRV_PCM_TRIGGER_START:
 		rsnd_dai_stream_init(io, substream);
 
-		ret = rsnd_platform_call(priv, dai, start, ssi_id);
-		if (ret < 0)
-			goto dai_trigger_end;
-
 		ret = rsnd_dai_call(init, io, priv);
 		if (ret < 0)
 			goto dai_trigger_end;
@@ -496,8 +517,6 @@
 
 		ret |= rsnd_dai_call(quit, io, priv);
 
-		ret |= rsnd_platform_call(priv, dai, stop, ssi_id);
-
 		rsnd_dai_stream_quit(io);
 		break;
 	default:
@@ -567,332 +586,157 @@
 	return 0;
 }
 
+static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
+				     u32 tx_mask, u32 rx_mask,
+				     int slots, int slot_width)
+{
+	struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
+	struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+	struct device *dev = rsnd_priv_to_dev(priv);
+
+	switch (slots) {
+	case 6:
+		/* TDM Extend Mode */
+		rsnd_set_slot(rdai, slots, 1);
+		break;
+	default:
+		dev_err(dev, "unsupported TDM slots (%d)\n", slots);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
 	.trigger	= rsnd_soc_dai_trigger,
 	.set_fmt	= rsnd_soc_dai_set_fmt,
+	.set_tdm_slot	= rsnd_soc_set_dai_tdm_slot,
 };
 
-#define rsnd_path_add(priv, io, type)				\
-({								\
-	struct rsnd_mod *mod;					\
-	int ret = 0;						\
-	int id = -1;						\
-								\
-	if (rsnd_is_enable_path(io, type)) {			\
-		id = rsnd_info_id(priv, io, type);		\
-		if (id >= 0) {					\
-			mod = rsnd_##type##_mod_get(priv, id);	\
-			ret = rsnd_dai_connect(mod, io);	\
-		}						\
-	}							\
-	ret;							\
-})
-
-#define rsnd_path_remove(priv, io, type)			\
-{								\
-	struct rsnd_mod *mod;					\
-	int id = -1;						\
-								\
-	if (rsnd_is_enable_path(io, type)) {			\
-		id = rsnd_info_id(priv, io, type);		\
-		if (id >= 0) {					\
-			mod = rsnd_##type##_mod_get(priv, id);	\
-			rsnd_dai_disconnect(mod, io);		\
-		}						\
-	}							\
-}
-
-void rsnd_path_parse(struct rsnd_priv *priv,
-		     struct rsnd_dai_stream *io)
+void rsnd_parse_connect_common(struct rsnd_dai *rdai,
+		struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
+		struct device_node *node,
+		struct device_node *playback,
+		struct device_node *capture)
 {
-	struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
-	struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
-	struct rsnd_mod *src = rsnd_io_to_mod_src(io);
-	struct rsnd_mod *cmd;
-	struct device *dev = rsnd_priv_to_dev(priv);
-	u32 data;
+	struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+	struct device_node *np;
+	struct rsnd_mod *mod;
+	int i;
 
-	/* Gen1 is not supported */
-	if (rsnd_is_gen1(priv))
+	if (!node)
 		return;
 
-	if (!mix && !dvc)
-		return;
-
-	if (mix) {
-		struct rsnd_dai *rdai;
-		int i;
-		u32 path[] = {
-			[0] = 0,
-			[1] = 1 << 0,
-			[2] = 0,
-			[3] = 0,
-			[4] = 0,
-			[5] = 1 << 8
-		};
-
-		/*
-		 * it is assuming that integrater is well understanding about
-		 * data path. Here doesn't check impossible connection,
-		 * like src2 + src5
-		 */
-		data = 0;
-		for_each_rsnd_dai(rdai, priv, i) {
-			io = &rdai->playback;
-			if (mix == rsnd_io_to_mod_mix(io))
-				data |= path[rsnd_mod_id(src)];
-
-			io = &rdai->capture;
-			if (mix == rsnd_io_to_mod_mix(io))
-				data |= path[rsnd_mod_id(src)];
-		}
-
-		/*
-		 * We can't use ctu = rsnd_io_ctu() here.
-		 * Since, ID of dvc/mix are 0 or 1 (= same as CMD number)
-		 * but ctu IDs are 0 - 7 (= CTU00 - CTU13)
-		 */
-		cmd = mix;
-	} else {
-		u32 path[] = {
-			[0] = 0x30000,
-			[1] = 0x30001,
-			[2] = 0x40000,
-			[3] = 0x10000,
-			[4] = 0x20000,
-			[5] = 0x40100
-		};
-
-		data = path[rsnd_mod_id(src)];
-
-		cmd = dvc;
+	i = 0;
+	for_each_child_of_node(node, np) {
+		mod = mod_get(priv, i);
+		if (np == playback)
+			rsnd_dai_connect(mod, &rdai->playback, mod->type);
+		if (np == capture)
+			rsnd_dai_connect(mod, &rdai->capture, mod->type);
+		i++;
 	}
 
-	dev_dbg(dev, "ctu/mix path = 0x%08x", data);
-
-	rsnd_mod_write(cmd, CMD_ROUTE_SLCT, data);
-
-	rsnd_mod_write(cmd, CMD_CTRL, 0x10);
+	of_node_put(node);
 }
 
-static int rsnd_path_init(struct rsnd_priv *priv,
-			  struct rsnd_dai *rdai,
-			  struct rsnd_dai_stream *io)
+static int rsnd_dai_probe(struct rsnd_priv *priv)
 {
+	struct device_node *dai_node;
+	struct device_node *dai_np;
+	struct device_node *playback, *capture;
+	struct rsnd_dai_stream *io_playback;
+	struct rsnd_dai_stream *io_capture;
+	struct snd_soc_dai_driver *rdrv, *drv;
+	struct rsnd_dai *rdai;
+	struct device *dev = rsnd_priv_to_dev(priv);
+	int nr, dai_i, io_i;
 	int ret;
 
-	/*
-	 * Gen1 is created by SRU/SSI, and this SRU is base module of
-	 * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
-	 *
-	 * Easy image is..
-	 *	Gen1 SRU = Gen2 SCU + SSIU + etc
-	 *
-	 * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
-	 * using fixed path.
-	 */
-
-	/* SSI */
-	ret = rsnd_path_add(priv, io, ssi);
-	if (ret < 0)
-		return ret;
-
-	/* SRC */
-	ret = rsnd_path_add(priv, io, src);
-	if (ret < 0)
-		return ret;
-
-	/* CTU */
-	ret = rsnd_path_add(priv, io, ctu);
-	if (ret < 0)
-		return ret;
-
-	/* MIX */
-	ret = rsnd_path_add(priv, io, mix);
-	if (ret < 0)
-		return ret;
-
-	/* DVC */
-	ret = rsnd_path_add(priv, io, dvc);
-	if (ret < 0)
-		return ret;
-
-	return ret;
-}
-
-static void rsnd_of_parse_dai(struct platform_device *pdev,
-			      const struct rsnd_of_data *of_data,
-			      struct rsnd_priv *priv)
-{
-	struct device_node *dai_node,	*dai_np;
-	struct device_node *ssi_node,	*ssi_np;
-	struct device_node *src_node,	*src_np;
-	struct device_node *ctu_node,	*ctu_np;
-	struct device_node *mix_node,	*mix_np;
-	struct device_node *dvc_node,	*dvc_np;
-	struct device_node *playback, *capture;
-	struct rsnd_dai_platform_info *dai_info;
-	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-	struct device *dev = &pdev->dev;
-	int nr, i;
-	int dai_i, ssi_i, src_i, ctu_i, mix_i, dvc_i;
-
-	if (!of_data)
-		return;
-
-	dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai");
-	if (!dai_node)
-		return;
-
+	dai_node = rsnd_dai_of_node(priv);
 	nr = of_get_child_count(dai_node);
-	if (!nr)
-		return;
-
-	dai_info = devm_kzalloc(dev,
-				sizeof(struct rsnd_dai_platform_info) * nr,
-				GFP_KERNEL);
-	if (!dai_info) {
-		dev_err(dev, "dai info allocation error\n");
-		return;
+	if (!nr) {
+		ret = -EINVAL;
+		goto rsnd_dai_probe_done;
 	}
 
-	info->dai_info_nr	= nr;
-	info->dai_info		= dai_info;
+	rdrv = devm_kzalloc(dev, sizeof(*rdrv) * nr, GFP_KERNEL);
+	rdai = devm_kzalloc(dev, sizeof(*rdai) * nr, GFP_KERNEL);
+	if (!rdrv || !rdai) {
+		ret = -ENOMEM;
+		goto rsnd_dai_probe_done;
+	}
 
-	ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
-	src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
-	ctu_node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu");
-	mix_node = of_get_child_by_name(dev->of_node, "rcar_sound,mix");
-	dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc");
-
-#define mod_parse(name)							\
-if (name##_node) {							\
-	struct rsnd_##name##_platform_info *name##_info;		\
-									\
-	name##_i = 0;							\
-	for_each_child_of_node(name##_node, name##_np) {		\
-		name##_info = info->name##_info + name##_i;		\
-									\
-		if (name##_np == playback)				\
-			dai_info->playback.name = name##_info;		\
-		if (name##_np == capture)				\
-			dai_info->capture.name = name##_info;		\
-									\
-		name##_i++;						\
-	}								\
-}
+	priv->rdai_nr	= nr;
+	priv->daidrv	= rdrv;
+	priv->rdai	= rdai;
 
 	/*
 	 * parse all dai
 	 */
 	dai_i = 0;
 	for_each_child_of_node(dai_node, dai_np) {
-		dai_info = info->dai_info + dai_i;
+		rdai		= rsnd_rdai_get(priv, dai_i);
+		drv		= rdrv + dai_i;
+		io_playback	= &rdai->playback;
+		io_capture	= &rdai->capture;
 
-		for (i = 0;; i++) {
+		snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i);
 
-			playback = of_parse_phandle(dai_np, "playback", i);
-			capture  = of_parse_phandle(dai_np, "capture", i);
+		rdai->priv	= priv;
+		drv->name	= rdai->name;
+		drv->ops	= &rsnd_soc_dai_ops;
+
+		snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE,
+			 "DAI%d Playback", dai_i);
+		drv->playback.rates		= RSND_RATES;
+		drv->playback.formats		= RSND_FMTS;
+		drv->playback.channels_min	= 2;
+		drv->playback.channels_max	= 6;
+		drv->playback.stream_name	= rdai->playback.name;
+
+		snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
+			 "DAI%d Capture", dai_i);
+		drv->capture.rates		= RSND_RATES;
+		drv->capture.formats		= RSND_FMTS;
+		drv->capture.channels_min	= 2;
+		drv->capture.channels_max	= 6;
+		drv->capture.stream_name	= rdai->capture.name;
+
+		rdai->playback.rdai		= rdai;
+		rdai->capture.rdai		= rdai;
+		rsnd_set_slot(rdai, 2, 1); /* default */
+
+		for (io_i = 0;; io_i++) {
+			playback = of_parse_phandle(dai_np, "playback", io_i);
+			capture  = of_parse_phandle(dai_np, "capture", io_i);
 
 			if (!playback && !capture)
 				break;
 
-			mod_parse(ssi);
-			mod_parse(src);
-			mod_parse(ctu);
-			mod_parse(mix);
-			mod_parse(dvc);
+			rsnd_parse_connect_ssi(rdai, playback, capture);
+			rsnd_parse_connect_src(rdai, playback, capture);
+			rsnd_parse_connect_ctu(rdai, playback, capture);
+			rsnd_parse_connect_mix(rdai, playback, capture);
+			rsnd_parse_connect_dvc(rdai, playback, capture);
 
 			of_node_put(playback);
 			of_node_put(capture);
 		}
 
 		dai_i++;
-	}
-}
 
-static int rsnd_dai_probe(struct platform_device *pdev,
-			  const struct rsnd_of_data *of_data,
-			  struct rsnd_priv *priv)
-{
-	struct snd_soc_dai_driver *drv;
-	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-	struct rsnd_dai *rdai;
-	struct rsnd_ssi_platform_info *pmod, *cmod;
-	struct device *dev = rsnd_priv_to_dev(priv);
-	int dai_nr;
-	int i;
-
-	rsnd_of_parse_dai(pdev, of_data, priv);
-
-	dai_nr = info->dai_info_nr;
-	if (!dai_nr) {
-		dev_err(dev, "no dai\n");
-		return -EIO;
+		dev_dbg(dev, "%s (%s/%s)\n", rdai->name,
+			rsnd_io_to_mod_ssi(io_playback) ? "play"    : " -- ",
+			rsnd_io_to_mod_ssi(io_capture) ? "capture" : "  --   ");
 	}
 
-	drv  = devm_kzalloc(dev, sizeof(*drv)  * dai_nr, GFP_KERNEL);
-	rdai = devm_kzalloc(dev, sizeof(*rdai) * dai_nr, GFP_KERNEL);
-	if (!drv || !rdai) {
-		dev_err(dev, "dai allocate failed\n");
-		return -ENOMEM;
-	}
+	ret = 0;
 
-	priv->rdai_nr	= dai_nr;
-	priv->daidrv	= drv;
-	priv->rdai	= rdai;
+rsnd_dai_probe_done:
+	of_node_put(dai_node);
 
-	for (i = 0; i < dai_nr; i++) {
-
-		pmod = info->dai_info[i].playback.ssi;
-		cmod = info->dai_info[i].capture.ssi;
-
-		/*
-		 *	init rsnd_dai
-		 */
-		snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i);
-		rdai[i].priv = priv;
-
-		/*
-		 *	init snd_soc_dai_driver
-		 */
-		drv[i].name	= rdai[i].name;
-		drv[i].ops	= &rsnd_soc_dai_ops;
-		if (pmod) {
-			snprintf(rdai[i].playback.name, RSND_DAI_NAME_SIZE,
-				 "DAI%d Playback", i);
-
-			drv[i].playback.rates		= RSND_RATES;
-			drv[i].playback.formats		= RSND_FMTS;
-			drv[i].playback.channels_min	= 2;
-			drv[i].playback.channels_max	= 2;
-			drv[i].playback.stream_name	= rdai[i].playback.name;
-
-			rdai[i].playback.info = &info->dai_info[i].playback;
-			rdai[i].playback.rdai = rdai + i;
-			rsnd_path_init(priv, &rdai[i], &rdai[i].playback);
-		}
-		if (cmod) {
-			snprintf(rdai[i].capture.name, RSND_DAI_NAME_SIZE,
-				 "DAI%d Capture", i);
-
-			drv[i].capture.rates		= RSND_RATES;
-			drv[i].capture.formats		= RSND_FMTS;
-			drv[i].capture.channels_min	= 2;
-			drv[i].capture.channels_max	= 2;
-			drv[i].capture.stream_name	= rdai[i].capture.name;
-
-			rdai[i].capture.info = &info->dai_info[i].capture;
-			rdai[i].capture.rdai = rdai + i;
-			rsnd_path_init(priv, &rdai[i], &rdai[i].capture);
-		}
-
-		dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name,
-			pmod ? "play"    : " -- ",
-			cmod ? "capture" : "  --   ");
-	}
-
-	return 0;
+	return ret;
 }
 
 /*
@@ -1033,14 +877,13 @@
 			    void (*update)(struct rsnd_dai_stream *io,
 					   struct rsnd_mod *mod))
 {
-	struct snd_soc_card *soc_card = rtd->card;
 	struct snd_card *card = rtd->card->snd_card;
 	struct snd_kcontrol *kctrl;
 	struct snd_kcontrol_new knew = {
 		.iface		= SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name		= name,
 		.info		= rsnd_kctrl_info,
-		.index		= rtd - soc_card->rtd,
+		.index		= rtd->num,
 		.get		= rsnd_kctrl_get,
 		.put		= rsnd_kctrl_put,
 		.private_value	= (unsigned long)cfg,
@@ -1077,10 +920,14 @@
 		     void (*update)(struct rsnd_dai_stream *io,
 				    struct rsnd_mod *mod),
 		     struct rsnd_kctrl_cfg_m *_cfg,
+		     int ch_size,
 		     u32 max)
 {
+	if (ch_size > RSND_DVC_CHANNELS)
+		return -EINVAL;
+
 	_cfg->cfg.max	= max;
-	_cfg->cfg.size	= RSND_DVC_CHANNELS;
+	_cfg->cfg.size	= ch_size;
 	_cfg->cfg.val	= _cfg->val;
 	return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update);
 }
@@ -1161,6 +1008,9 @@
 
 	ret = rsnd_dai_call(probe, io, priv);
 	if (ret == -EAGAIN) {
+		struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+		int i;
+
 		/*
 		 * Fallback to PIO mode
 		 */
@@ -1175,10 +1025,12 @@
 		rsnd_dai_call(remove, io, priv);
 
 		/*
-		 * remove SRC/DVC from DAI,
+		 * remove all mod from io
+		 * and, re connect ssi
 		 */
-		rsnd_path_remove(priv, io, src);
-		rsnd_path_remove(priv, io, dvc);
+		for (i = 0; i < RSND_MOD_MAX; i++)
+			rsnd_dai_disconnect((io)->mod[i], io, i);
+		rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI);
 
 		/*
 		 * fallback
@@ -1200,33 +1052,25 @@
  */
 static int rsnd_probe(struct platform_device *pdev)
 {
-	struct rcar_snd_info *info;
 	struct rsnd_priv *priv;
 	struct device *dev = &pdev->dev;
 	struct rsnd_dai *rdai;
 	const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev);
-	const struct rsnd_of_data *of_data;
-	int (*probe_func[])(struct platform_device *pdev,
-			    const struct rsnd_of_data *of_data,
-			    struct rsnd_priv *priv) = {
+	int (*probe_func[])(struct rsnd_priv *priv) = {
 		rsnd_gen_probe,
 		rsnd_dma_probe,
 		rsnd_ssi_probe,
+		rsnd_ssiu_probe,
 		rsnd_src_probe,
 		rsnd_ctu_probe,
 		rsnd_mix_probe,
 		rsnd_dvc_probe,
+		rsnd_cmd_probe,
 		rsnd_adg_probe,
 		rsnd_dai_probe,
 	};
 	int ret, i;
 
-	info = devm_kzalloc(&pdev->dev, sizeof(struct rcar_snd_info),
-			    GFP_KERNEL);
-	if (!info)
-		return -ENOMEM;
-	of_data = of_id->data;
-
 	/*
 	 *	init priv data
 	 */
@@ -1237,14 +1081,14 @@
 	}
 
 	priv->pdev	= pdev;
-	priv->info	= info;
+	priv->flags	= (unsigned long)of_id->data;
 	spin_lock_init(&priv->lock);
 
 	/*
 	 *	init each module
 	 */
 	for (i = 0; i < ARRAY_SIZE(probe_func); i++) {
-		ret = probe_func[i](pdev, of_data, priv);
+		ret = probe_func[i](priv);
 		if (ret)
 			return ret;
 	}
@@ -1297,13 +1141,15 @@
 {
 	struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
 	struct rsnd_dai *rdai;
-	void (*remove_func[])(struct platform_device *pdev,
-			      struct rsnd_priv *priv) = {
+	void (*remove_func[])(struct rsnd_priv *priv) = {
 		rsnd_ssi_remove,
+		rsnd_ssiu_remove,
 		rsnd_src_remove,
 		rsnd_ctu_remove,
 		rsnd_mix_remove,
 		rsnd_dvc_remove,
+		rsnd_cmd_remove,
+		rsnd_adg_remove,
 	};
 	int ret = 0, i;
 
@@ -1315,7 +1161,7 @@
 	}
 
 	for (i = 0; i < ARRAY_SIZE(remove_func); i++)
-		remove_func[i](pdev, priv);
+		remove_func[i](priv);
 
 	snd_soc_unregister_component(&pdev->dev);
 	snd_soc_unregister_platform(&pdev->dev);
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
index 3cb214a..d53a225 100644
--- a/sound/soc/sh/rcar/ctu.c
+++ b/sound/soc/sh/rcar/ctu.c
@@ -13,7 +13,6 @@
 #define CTU_NAME "ctu"
 
 struct rsnd_ctu {
-	struct rsnd_ctu_platform_info *info; /* rcar_snd.h */
 	struct rsnd_mod mod;
 };
 
@@ -24,6 +23,7 @@
 		     ((pos) = (struct rsnd_ctu *)(priv)->ctu + i);	\
 	     i++)
 
+#define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id)
 #define rsnd_ctu_initialize_lock(mod)	__rsnd_ctu_initialize_lock(mod, 1)
 #define rsnd_ctu_initialize_unlock(mod)	__rsnd_ctu_initialize_lock(mod, 0)
 static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable)
@@ -31,6 +31,13 @@
 	rsnd_mod_write(mod, CTU_CTUIR, enable);
 }
 
+static int rsnd_ctu_probe_(struct rsnd_mod *mod,
+			   struct rsnd_dai_stream *io,
+			   struct rsnd_priv *priv)
+{
+	return rsnd_cmd_attach(io, rsnd_mod_id(mod) / 4);
+}
+
 static int rsnd_ctu_init(struct rsnd_mod *mod,
 			 struct rsnd_dai_stream *io,
 			 struct rsnd_priv *priv)
@@ -57,6 +64,7 @@
 
 static struct rsnd_mod_ops rsnd_ctu_ops = {
 	.name		= CTU_NAME,
+	.probe		= rsnd_ctu_probe_,
 	.init		= rsnd_ctu_init,
 	.quit		= rsnd_ctu_quit,
 };
@@ -66,51 +74,13 @@
 	if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv)))
 		id = 0;
 
-	return rsnd_mod_get((struct rsnd_ctu *)(priv->ctu) + id);
+	return rsnd_mod_get(rsnd_ctu_get(priv, id));
 }
 
-static void rsnd_of_parse_ctu(struct platform_device *pdev,
-		       const struct rsnd_of_data *of_data,
-		       struct rsnd_priv *priv)
+int rsnd_ctu_probe(struct rsnd_priv *priv)
 {
 	struct device_node *node;
-	struct rsnd_ctu_platform_info *ctu_info;
-	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-	struct device *dev = &pdev->dev;
-	int nr;
-
-	if (!of_data)
-		return;
-
-	node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu");
-	if (!node)
-		return;
-
-	nr = of_get_child_count(node);
-	if (!nr)
-		goto rsnd_of_parse_ctu_end;
-
-	ctu_info = devm_kzalloc(dev,
-				sizeof(struct rsnd_ctu_platform_info) * nr,
-				GFP_KERNEL);
-	if (!ctu_info) {
-		dev_err(dev, "ctu info allocation error\n");
-		goto rsnd_of_parse_ctu_end;
-	}
-
-	info->ctu_info		= ctu_info;
-	info->ctu_info_nr	= nr;
-
-rsnd_of_parse_ctu_end:
-	of_node_put(node);
-
-}
-
-int rsnd_ctu_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv)
-{
-	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+	struct device_node *np;
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_ctu *ctu;
 	struct clk *clk;
@@ -121,20 +91,30 @@
 	if (rsnd_is_gen1(priv))
 		return 0;
 
-	rsnd_of_parse_ctu(pdev, of_data, priv);
+	node = rsnd_ctu_of_node(priv);
+	if (!node)
+		return 0; /* not used is not error */
 
-	nr = info->ctu_info_nr;
-	if (!nr)
-		return 0;
+	nr = of_get_child_count(node);
+	if (!nr) {
+		ret = -EINVAL;
+		goto rsnd_ctu_probe_done;
+	}
 
 	ctu = devm_kzalloc(dev, sizeof(*ctu) * nr, GFP_KERNEL);
-	if (!ctu)
-		return -ENOMEM;
+	if (!ctu) {
+		ret = -ENOMEM;
+		goto rsnd_ctu_probe_done;
+	}
 
 	priv->ctu_nr	= nr;
 	priv->ctu	= ctu;
 
-	for_each_rsnd_ctu(ctu, priv, i) {
+	i = 0;
+	ret = 0;
+	for_each_child_of_node(node, np) {
+		ctu = rsnd_ctu_get(priv, i);
+
 		/*
 		 * CTU00, CTU01, CTU02, CTU03 => CTU0
 		 * CTU10, CTU11, CTU12, CTU13 => CTU1
@@ -143,22 +123,27 @@
 			 CTU_NAME, i / 4);
 
 		clk = devm_clk_get(dev, name);
-		if (IS_ERR(clk))
-			return PTR_ERR(clk);
-
-		ctu->info = &info->ctu_info[i];
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			goto rsnd_ctu_probe_done;
+		}
 
 		ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
 				    clk, RSND_MOD_CTU, i);
 		if (ret)
-			return ret;
+			goto rsnd_ctu_probe_done;
+
+		i++;
 	}
 
-	return 0;
+
+rsnd_ctu_probe_done:
+	of_node_put(node);
+
+	return ret;
 }
 
-void rsnd_ctu_remove(struct platform_device *pdev,
-		     struct rsnd_priv *priv)
+void rsnd_ctu_remove(struct rsnd_priv *priv)
 {
 	struct rsnd_ctu *ctu;
 	int i;
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 5d084d0..418e6fd 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -22,21 +22,36 @@
 /* PDMACHCR */
 #define PDMACHCR_DE		(1 << 0)
 
+
+struct rsnd_dmaen {
+	struct dma_chan		*chan;
+};
+
+struct rsnd_dmapp {
+	int			dmapp_id;
+	u32			chcr;
+};
+
+struct rsnd_dma {
+	struct rsnd_mod		mod;
+	dma_addr_t		src_addr;
+	dma_addr_t		dst_addr;
+	union {
+		struct rsnd_dmaen en;
+		struct rsnd_dmapp pp;
+	} dma;
+};
+
 struct rsnd_dma_ctrl {
 	void __iomem *base;
+	int dmaen_num;
 	int dmapp_num;
 };
 
-struct rsnd_dma_ops {
-	char *name;
-	void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-	void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-	int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id,
-		    struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
-	void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-};
-
 #define rsnd_priv_to_dmac(p)	((struct rsnd_dma_ctrl *)(p)->dma)
+#define rsnd_mod_to_dma(_mod) container_of((_mod), struct rsnd_dma, mod)
+#define rsnd_dma_to_dmaen(dma)	(&(dma)->dma.en)
+#define rsnd_dma_to_dmapp(dma)	(&(dma)->dma.pp)
 
 /*
  *		Audio DMAC
@@ -77,18 +92,24 @@
 	rsnd_mod_interrupt(mod, __rsnd_dmaen_complete);
 }
 
-static void rsnd_dmaen_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
+static int rsnd_dmaen_stop(struct rsnd_mod *mod,
+			   struct rsnd_dai_stream *io,
+			   struct rsnd_priv *priv)
 {
+	struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
 	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
 
 	dmaengine_terminate_all(dmaen->chan);
+
+	return 0;
 }
 
-static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
+static int rsnd_dmaen_start(struct rsnd_mod *mod,
+			    struct rsnd_dai_stream *io,
+			    struct rsnd_priv *priv)
 {
+	struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
 	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
-	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
-	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
 	struct snd_pcm_substream *substream = io->substream;
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct dma_async_tx_descriptor *desc;
@@ -103,18 +124,20 @@
 
 	if (!desc) {
 		dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
-		return;
+		return -EIO;
 	}
 
 	desc->callback		= rsnd_dmaen_complete;
-	desc->callback_param	= mod;
+	desc->callback_param	= rsnd_mod_get(dma);
 
 	if (dmaengine_submit(desc) < 0) {
 		dev_err(dev, "dmaengine_submit() fail\n");
-		return;
+		return -EIO;
 	}
 
 	dma_async_issue_pending(dmaen->chan);
+
+	return 0;
 }
 
 struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
@@ -152,12 +175,29 @@
 		return rsnd_mod_dma_req(io, mod_to);
 }
 
-static int rsnd_dmaen_init(struct rsnd_dai_stream *io,
+static int rsnd_dmaen_remove(struct rsnd_mod *mod,
+			      struct rsnd_dai_stream *io,
+			      struct rsnd_priv *priv)
+{
+	struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
+	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
+
+	if (dmaen->chan)
+		dma_release_channel(dmaen->chan);
+
+	dmaen->chan = NULL;
+
+	return 0;
+}
+
+static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
 			   struct rsnd_dma *dma, int id,
 			   struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
 {
+	struct rsnd_mod *mod = rsnd_mod_get(dma);
 	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
+	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct dma_slave_config cfg = {};
 	int is_play = rsnd_io_is_play(io);
@@ -191,18 +231,20 @@
 	cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 	cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 
-	dev_dbg(dev, "%s %pad -> %pad\n",
-		dma->ops->name,
+	dev_dbg(dev, "%s[%d] %pad -> %pad\n",
+		rsnd_mod_name(mod), rsnd_mod_id(mod),
 		&cfg.src_addr, &cfg.dst_addr);
 
 	ret = dmaengine_slave_config(dmaen->chan, &cfg);
 	if (ret < 0)
-		goto rsnd_dma_init_err;
+		goto rsnd_dma_attach_err;
+
+	dmac->dmaen_num++;
 
 	return 0;
 
-rsnd_dma_init_err:
-	rsnd_dma_quit(io, dma);
+rsnd_dma_attach_err:
+	rsnd_dmaen_remove(mod, io, priv);
 rsnd_dma_channel_err:
 
 	/*
@@ -214,22 +256,11 @@
 	return -EAGAIN;
 }
 
-static void rsnd_dmaen_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
-{
-	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
-
-	if (dmaen->chan)
-		dma_release_channel(dmaen->chan);
-
-	dmaen->chan = NULL;
-}
-
-static struct rsnd_dma_ops rsnd_dmaen_ops = {
+static struct rsnd_mod_ops rsnd_dmaen_ops = {
 	.name	= "audmac",
 	.start	= rsnd_dmaen_start,
 	.stop	= rsnd_dmaen_stop,
-	.init	= rsnd_dmaen_init,
-	.quit	= rsnd_dmaen_quit,
+	.remove	= rsnd_dmaen_remove,
 };
 
 /*
@@ -307,7 +338,7 @@
 	 (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id))
 static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg)
 {
-	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+	struct rsnd_mod *mod = rsnd_mod_get(dma);
 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
 	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
 	struct device *dev = rsnd_priv_to_dev(priv);
@@ -319,38 +350,48 @@
 
 static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg)
 {
-	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+	struct rsnd_mod *mod = rsnd_mod_get(dma);
 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
 	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
 
 	return ioread32(rsnd_dmapp_addr(dmac, dma, reg));
 }
 
-static void rsnd_dmapp_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
+static int rsnd_dmapp_stop(struct rsnd_mod *mod,
+			   struct rsnd_dai_stream *io,
+			   struct rsnd_priv *priv)
 {
+	struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
 	int i;
 
 	rsnd_dmapp_write(dma, 0, PDMACHCR);
 
 	for (i = 0; i < 1024; i++) {
 		if (0 == rsnd_dmapp_read(dma, PDMACHCR))
-			return;
+			return 0;
 		udelay(1);
 	}
+
+	return -EIO;
 }
 
-static void rsnd_dmapp_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
+static int rsnd_dmapp_start(struct rsnd_mod *mod,
+			    struct rsnd_dai_stream *io,
+			    struct rsnd_priv *priv)
 {
+	struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
 	struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
 
 	rsnd_dmapp_write(dma, dma->src_addr,	PDMASAR);
 	rsnd_dmapp_write(dma, dma->dst_addr,	PDMADAR);
 	rsnd_dmapp_write(dma, dmapp->chcr,	PDMACHCR);
+
+	return 0;
 }
 
-static int rsnd_dmapp_init(struct rsnd_dai_stream *io,
-			   struct rsnd_dma *dma, int id,
-			   struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
+static int rsnd_dmapp_attach(struct rsnd_dai_stream *io,
+			     struct rsnd_dma *dma, int id,
+			     struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
 {
 	struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
@@ -362,19 +403,16 @@
 
 	dmac->dmapp_num++;
 
-	rsnd_dmapp_stop(io, dma);
-
 	dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n",
 		dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr);
 
 	return 0;
 }
 
-static struct rsnd_dma_ops rsnd_dmapp_ops = {
+static struct rsnd_mod_ops rsnd_dmapp_ops = {
 	.name	= "audmac-pp",
 	.start	= rsnd_dmapp_start,
 	.stop	= rsnd_dmapp_stop,
-	.init	= rsnd_dmapp_init,
 	.quit	= rsnd_dmapp_stop,
 };
 
@@ -497,13 +535,12 @@
 }
 
 #define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */
-static void rsnd_dma_of_path(struct rsnd_dma *dma,
+static void rsnd_dma_of_path(struct rsnd_mod *this,
 			     struct rsnd_dai_stream *io,
 			     int is_play,
 			     struct rsnd_mod **mod_from,
 			     struct rsnd_mod **mod_to)
 {
-	struct rsnd_mod *this = rsnd_dma_to_mod(dma);
 	struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
 	struct rsnd_mod *src = rsnd_io_to_mod_src(io);
 	struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io);
@@ -513,7 +550,7 @@
 	struct rsnd_mod *mod_start, *mod_end;
 	struct rsnd_priv *priv = rsnd_mod_to_priv(this);
 	struct device *dev = rsnd_priv_to_dev(priv);
-	int nr, i;
+	int nr, i, idx;
 
 	if (!ssi)
 		return;
@@ -542,23 +579,24 @@
 	mod_start	= (is_play) ? NULL : ssi;
 	mod_end		= (is_play) ? ssi  : NULL;
 
-	mod[0] = mod_start;
+	idx = 0;
+	mod[idx++] = mod_start;
 	for (i = 1; i < nr; i++) {
 		if (src) {
-			mod[i] = src;
+			mod[idx++] = src;
 			src = NULL;
 		} else if (ctu) {
-			mod[i] = ctu;
+			mod[idx++] = ctu;
 			ctu = NULL;
 		} else if (mix) {
-			mod[i] = mix;
+			mod[idx++] = mix;
 			mix = NULL;
 		} else if (dvc) {
-			mod[i] = dvc;
+			mod[idx++] = dvc;
 			dvc = NULL;
 		}
 	}
-	mod[i] = mod_end;
+	mod[idx] = mod_end;
 
 	/*
 	 *		| SSI | SRC |
@@ -567,8 +605,8 @@
 	 * !is_play	|  *  |  o  |
 	 */
 	if ((this == ssi) == (is_play)) {
-		*mod_from	= mod[nr - 1];
-		*mod_to		= mod[nr];
+		*mod_from	= mod[idx - 1];
+		*mod_to		= mod[idx];
 	} else {
 		*mod_from	= mod[0];
 		*mod_to		= mod[1];
@@ -576,7 +614,7 @@
 
 	dev_dbg(dev, "module connection (this is %s[%d])\n",
 		rsnd_mod_name(this), rsnd_mod_id(this));
-	for (i = 0; i <= nr; i++) {
+	for (i = 0; i <= idx; i++) {
 		dev_dbg(dev, "  %s[%d]%s\n",
 		       rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]),
 		       (mod[i] == *mod_from) ? " from" :
@@ -584,36 +622,22 @@
 	}
 }
 
-void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
+struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io,
+				 struct rsnd_mod *mod, int id)
 {
-	dma->ops->stop(io, dma);
-}
-
-void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
-{
-	dma->ops->start(io, dma);
-}
-
-void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
-{
-	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
-	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
-
-	if (!dmac)
-		return;
-
-	dma->ops->quit(io, dma);
-}
-
-int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id)
-{
+	struct rsnd_mod *dma_mod;
 	struct rsnd_mod *mod_from = NULL;
 	struct rsnd_mod *mod_to = NULL;
 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
 	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+	struct rsnd_dma *dma;
 	struct device *dev = rsnd_priv_to_dev(priv);
+	struct rsnd_mod_ops *ops;
+	enum rsnd_mod_type type;
+	int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id,
+		      struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
 	int is_play = rsnd_io_is_play(io);
+	int ret, dma_id;
 
 	/*
 	 * DMA failed. try to PIO mode
@@ -622,35 +646,64 @@
 	 *	rsnd_rdai_continuance_probe()
 	 */
 	if (!dmac)
-		return -EAGAIN;
+		return ERR_PTR(-EAGAIN);
 
-	rsnd_dma_of_path(dma, io, is_play, &mod_from, &mod_to);
+	dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+	if (!dma)
+		return ERR_PTR(-ENOMEM);
+
+	rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to);
 
 	dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
 	dma->dst_addr = rsnd_dma_addr(io, mod_to,   is_play, 0);
 
 	/* for Gen2 */
-	if (mod_from && mod_to)
-		dma->ops = &rsnd_dmapp_ops;
-	else
-		dma->ops = &rsnd_dmaen_ops;
+	if (mod_from && mod_to) {
+		ops	= &rsnd_dmapp_ops;
+		attach	= rsnd_dmapp_attach;
+		dma_id	= dmac->dmapp_num;
+		type	= RSND_MOD_AUDMAPP;
+	} else {
+		ops	= &rsnd_dmaen_ops;
+		attach	= rsnd_dmaen_attach;
+		dma_id	= dmac->dmaen_num;
+		type	= RSND_MOD_AUDMA;
+	}
 
 	/* for Gen1, overwrite */
-	if (rsnd_is_gen1(priv))
-		dma->ops = &rsnd_dmaen_ops;
+	if (rsnd_is_gen1(priv)) {
+		ops	= &rsnd_dmaen_ops;
+		attach	= rsnd_dmaen_attach;
+		dma_id	= dmac->dmaen_num;
+		type	= RSND_MOD_AUDMA;
+	}
 
-	dev_dbg(dev, "%s %s[%d] -> %s[%d]\n",
-		dma->ops->name,
+	dma_mod = rsnd_mod_get(dma);
+
+	ret = rsnd_mod_init(priv, dma_mod,
+			    ops, NULL, type, dma_id);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n",
+		rsnd_mod_name(dma_mod), rsnd_mod_id(dma_mod),
 		rsnd_mod_name(mod_from), rsnd_mod_id(mod_from),
 		rsnd_mod_name(mod_to),   rsnd_mod_id(mod_to));
 
-	return dma->ops->init(io, dma, id, mod_from, mod_to);
+	ret = attach(io, dma, id, mod_from, mod_to);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	ret = rsnd_dai_connect(dma_mod, io, type);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	return rsnd_mod_get(dma);
 }
 
-int rsnd_dma_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv)
+int rsnd_dma_probe(struct rsnd_priv *priv)
 {
+	struct platform_device *pdev = rsnd_priv_to_pdev(priv);
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_dma_ctrl *dmac;
 	struct resource *res;
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
index 58f6909..d45ffe4 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/sh/rcar/dvc.c
@@ -15,7 +15,6 @@
 #define DVC_NAME "dvc"
 
 struct rsnd_dvc {
-	struct rsnd_dvc_platform_info *info; /* rcar_snd.h */
 	struct rsnd_mod mod;
 	struct rsnd_kctrl_cfg_m volume;
 	struct rsnd_kctrl_cfg_m mute;
@@ -24,6 +23,7 @@
 	struct rsnd_kctrl_cfg_s rdown;	/* Ramp Rate Down */
 };
 
+#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
 #define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
 #define rsnd_dvc_of_node(priv) \
 	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
@@ -64,79 +64,142 @@
 	"0.125 dB/8192 steps",	 /* 10111 */
 };
 
-static void rsnd_dvc_soft_reset(struct rsnd_mod *mod)
+static void rsnd_dvc_activation(struct rsnd_mod *mod)
 {
 	rsnd_mod_write(mod, DVC_SWRSR, 0);
 	rsnd_mod_write(mod, DVC_SWRSR, 1);
 }
 
-#define rsnd_dvc_initialize_lock(mod)	__rsnd_dvc_initialize_lock(mod, 1)
-#define rsnd_dvc_initialize_unlock(mod)	__rsnd_dvc_initialize_lock(mod, 0)
-static void __rsnd_dvc_initialize_lock(struct rsnd_mod *mod, u32 enable)
+static void rsnd_dvc_halt(struct rsnd_mod *mod)
 {
-	rsnd_mod_write(mod, DVC_DVUIR, enable);
+	rsnd_mod_write(mod, DVC_DVUIR, 1);
+	rsnd_mod_write(mod, DVC_SWRSR, 0);
 }
 
-static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
-				   struct rsnd_mod *mod)
+#define rsnd_dvc_get_vrpdr(dvc) (dvc->rup.val << 8 | dvc->rdown.val)
+#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (dvc->volume.val[0] >> 13))
+
+static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
+					      struct rsnd_mod *mod)
 {
 	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
 	u32 val[RSND_DVC_CHANNELS];
-	u32 dvucr = 0;
-	u32 mute = 0;
 	int i;
 
-	for (i = 0; i < dvc->mute.cfg.size; i++)
-		mute |= (!!dvc->mute.cfg.val[i]) << i;
+	/* Enable Ramp */
+	if (dvc->ren.val)
+		for (i = 0; i < RSND_DVC_CHANNELS; i++)
+			val[i] = dvc->volume.cfg.max;
+	else
+		for (i = 0; i < RSND_DVC_CHANNELS; i++)
+			val[i] = dvc->volume.val[i];
 
-	/* Disable DVC Register access */
-	rsnd_mod_write(mod, DVC_DVUER, 0);
+	/* Enable Digital Volume */
+	rsnd_mod_write(mod, DVC_VOL0R, val[0]);
+	rsnd_mod_write(mod, DVC_VOL1R, val[1]);
+	rsnd_mod_write(mod, DVC_VOL2R, val[2]);
+	rsnd_mod_write(mod, DVC_VOL3R, val[3]);
+	rsnd_mod_write(mod, DVC_VOL4R, val[4]);
+	rsnd_mod_write(mod, DVC_VOL5R, val[5]);
+	rsnd_mod_write(mod, DVC_VOL6R, val[6]);
+	rsnd_mod_write(mod, DVC_VOL7R, val[7]);
+}
+
+static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,
+				 struct rsnd_mod *mod)
+{
+	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+	u32 adinr = 0;
+	u32 dvucr = 0;
+	u32 vrctr = 0;
+	u32 vrpdr = 0;
+	u32 vrdbr = 0;
+
+	adinr = rsnd_get_adinr_bit(mod, io) |
+		rsnd_get_adinr_chan(mod, io);
+
+	/* Enable Digital Volume, Zero Cross Mute Mode */
+	dvucr |= 0x101;
 
 	/* Enable Ramp */
 	if (dvc->ren.val) {
 		dvucr |= 0x10;
 
-		/* Digital Volume Max */
-		for (i = 0; i < RSND_DVC_CHANNELS; i++)
-			val[i] = dvc->volume.cfg.max;
-
-		rsnd_mod_write(mod, DVC_VRCTR, 0xff);
-		rsnd_mod_write(mod, DVC_VRPDR, dvc->rup.val << 8 |
-					       dvc->rdown.val);
 		/*
 		 * FIXME !!
 		 * use scale-downed Digital Volume
 		 * as Volume Ramp
 		 * 7F FFFF -> 3FF
 		 */
-		rsnd_mod_write(mod, DVC_VRDBR,
-			       0x3ff - (dvc->volume.val[0] >> 13));
-
-	} else {
-		for (i = 0; i < RSND_DVC_CHANNELS; i++)
-			val[i] = dvc->volume.val[i];
+		vrctr = 0xff;
+		vrpdr = rsnd_dvc_get_vrpdr(dvc);
+		vrdbr = rsnd_dvc_get_vrdbr(dvc);
 	}
 
-	/* Enable Digital Volume */
-	dvucr |= 0x100;
-	rsnd_mod_write(mod, DVC_VOL0R, val[0]);
-	rsnd_mod_write(mod, DVC_VOL1R, val[1]);
+	/* Initialize operation */
+	rsnd_mod_write(mod, DVC_DVUIR, 1);
 
-	/*  Enable Mute */
-	if (mute) {
-		dvucr |= 0x1;
-		rsnd_mod_write(mod, DVC_ZCMCR, mute);
-	}
-
+	/* General Information */
+	rsnd_mod_write(mod, DVC_ADINR, adinr);
 	rsnd_mod_write(mod, DVC_DVUCR, dvucr);
 
+	/* Volume Ramp Parameter */
+	rsnd_mod_write(mod, DVC_VRCTR, vrctr);
+	rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
+	rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
+
+	/* Digital Volume Function Parameter */
+	rsnd_dvc_volume_parameter(io, mod);
+
+	/* cancel operation */
+	rsnd_mod_write(mod, DVC_DVUIR, 0);
+}
+
+static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
+				   struct rsnd_mod *mod)
+{
+	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+	u32 zcmcr = 0;
+	u32 vrpdr = 0;
+	u32 vrdbr = 0;
+	int i;
+
+	for (i = 0; i < dvc->mute.cfg.size; i++)
+		zcmcr |= (!!dvc->mute.cfg.val[i]) << i;
+
+	if (dvc->ren.val) {
+		vrpdr = rsnd_dvc_get_vrpdr(dvc);
+		vrdbr = rsnd_dvc_get_vrdbr(dvc);
+	}
+
+	/* Disable DVC Register access */
+	rsnd_mod_write(mod, DVC_DVUER, 0);
+
+	/* Zero Cross Mute Function */
+	rsnd_mod_write(mod, DVC_ZCMCR, zcmcr);
+
+	/* Volume Ramp Function */
+	rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
+	rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
+	/* add DVC_VRWTR here */
+
+	/* Digital Volume Function Parameter */
+	rsnd_dvc_volume_parameter(io, mod);
+
 	/* Enable DVC Register access */
 	rsnd_mod_write(mod, DVC_DVUER, 1);
 }
 
-static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod,
-				struct rsnd_dai_stream *io,
-				struct rsnd_priv *priv)
+static int rsnd_dvc_probe_(struct rsnd_mod *mod,
+			   struct rsnd_dai_stream *io,
+			   struct rsnd_priv *priv)
+{
+	return rsnd_cmd_attach(io, rsnd_mod_id(mod));
+}
+
+static int rsnd_dvc_remove_(struct rsnd_mod *mod,
+			    struct rsnd_dai_stream *io,
+			    struct rsnd_priv *priv)
 {
 	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
 
@@ -155,19 +218,12 @@
 {
 	rsnd_mod_power_on(mod);
 
-	rsnd_dvc_soft_reset(mod);
+	rsnd_dvc_activation(mod);
 
-	rsnd_dvc_initialize_lock(mod);
+	rsnd_dvc_volume_init(io, mod);
 
-	rsnd_path_parse(priv, io);
-
-	rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io));
-
-	/* ch0/ch1 Volume */
 	rsnd_dvc_volume_update(io, mod);
 
-	rsnd_adg_set_cmd_timsel_gen2(mod, io);
-
 	return 0;
 }
 
@@ -175,37 +231,20 @@
 			 struct rsnd_dai_stream *io,
 			 struct rsnd_priv *priv)
 {
+	rsnd_dvc_halt(mod);
+
 	rsnd_mod_power_off(mod);
 
 	return 0;
 }
 
-static int rsnd_dvc_start(struct rsnd_mod *mod,
-			  struct rsnd_dai_stream *io,
-			  struct rsnd_priv *priv)
-{
-	rsnd_dvc_initialize_unlock(mod);
-
-	rsnd_mod_write(mod, CMD_CTRL, 0x10);
-
-	return 0;
-}
-
-static int rsnd_dvc_stop(struct rsnd_mod *mod,
-			 struct rsnd_dai_stream *io,
-			 struct rsnd_priv *priv)
-{
-	rsnd_mod_write(mod, CMD_CTRL, 0);
-
-	return 0;
-}
-
 static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
 			    struct rsnd_dai_stream *io,
 			    struct snd_soc_pcm_runtime *rtd)
 {
 	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
 	int is_play = rsnd_io_is_play(io);
+	int slots = rsnd_get_slot(io);
 	int ret;
 
 	/* Volume */
@@ -213,7 +252,8 @@
 			is_play ?
 			"DVC Out Playback Volume" : "DVC In Capture Volume",
 			rsnd_dvc_volume_update,
-			&dvc->volume, 0x00800000 - 1);
+			&dvc->volume, slots,
+			0x00800000 - 1);
 	if (ret < 0)
 		return ret;
 
@@ -222,7 +262,8 @@
 			is_play ?
 			"DVC Out Mute Switch" : "DVC In Mute Switch",
 			rsnd_dvc_volume_update,
-			&dvc->mute, 1);
+			&dvc->mute,  slots,
+			1);
 	if (ret < 0)
 		return ret;
 
@@ -269,11 +310,10 @@
 static struct rsnd_mod_ops rsnd_dvc_ops = {
 	.name		= DVC_NAME,
 	.dma_req	= rsnd_dvc_dma_req,
-	.remove		= rsnd_dvc_remove_gen2,
+	.probe		= rsnd_dvc_probe_,
+	.remove		= rsnd_dvc_remove_,
 	.init		= rsnd_dvc_init,
 	.quit		= rsnd_dvc_quit,
-	.start		= rsnd_dvc_start,
-	.stop		= rsnd_dvc_stop,
 	.pcm_new	= rsnd_dvc_pcm_new,
 };
 
@@ -282,50 +322,13 @@
 	if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv)))
 		id = 0;
 
-	return rsnd_mod_get((struct rsnd_dvc *)(priv->dvc) + id);
+	return rsnd_mod_get(rsnd_dvc_get(priv, id));
 }
 
-static void rsnd_of_parse_dvc(struct platform_device *pdev,
-			      const struct rsnd_of_data *of_data,
-			      struct rsnd_priv *priv)
+int rsnd_dvc_probe(struct rsnd_priv *priv)
 {
 	struct device_node *node;
-	struct rsnd_dvc_platform_info *dvc_info;
-	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-	struct device *dev = &pdev->dev;
-	int nr;
-
-	if (!of_data)
-		return;
-
-	node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc");
-	if (!node)
-		return;
-
-	nr = of_get_child_count(node);
-	if (!nr)
-		goto rsnd_of_parse_dvc_end;
-
-	dvc_info = devm_kzalloc(dev,
-				sizeof(struct rsnd_dvc_platform_info) * nr,
-				GFP_KERNEL);
-	if (!dvc_info) {
-		dev_err(dev, "dvc info allocation error\n");
-		goto rsnd_of_parse_dvc_end;
-	}
-
-	info->dvc_info		= dvc_info;
-	info->dvc_info_nr	= nr;
-
-rsnd_of_parse_dvc_end:
-	of_node_put(node);
-}
-
-int rsnd_dvc_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv)
-{
-	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+	struct device_node *np;
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_dvc *dvc;
 	struct clk *clk;
@@ -336,40 +339,54 @@
 	if (rsnd_is_gen1(priv))
 		return 0;
 
-	rsnd_of_parse_dvc(pdev, of_data, priv);
+	node = rsnd_dvc_of_node(priv);
+	if (!node)
+		return 0; /* not used is not error */
 
-	nr = info->dvc_info_nr;
-	if (!nr)
-		return 0;
+	nr = of_get_child_count(node);
+	if (!nr) {
+		ret = -EINVAL;
+		goto rsnd_dvc_probe_done;
+	}
 
 	dvc	= devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL);
-	if (!dvc)
-		return -ENOMEM;
+	if (!dvc) {
+		ret = -ENOMEM;
+		goto rsnd_dvc_probe_done;
+	}
 
 	priv->dvc_nr	= nr;
 	priv->dvc	= dvc;
 
-	for_each_rsnd_dvc(dvc, priv, i) {
+	i = 0;
+	ret = 0;
+	for_each_child_of_node(node, np) {
+		dvc = rsnd_dvc_get(priv, i);
+
 		snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d",
 			 DVC_NAME, i);
 
 		clk = devm_clk_get(dev, name);
-		if (IS_ERR(clk))
-			return PTR_ERR(clk);
-
-		dvc->info = &info->dvc_info[i];
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			goto rsnd_dvc_probe_done;
+		}
 
 		ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
 			      clk, RSND_MOD_DVC, i);
 		if (ret)
-			return ret;
+			goto rsnd_dvc_probe_done;
+
+		i++;
 	}
 
-	return 0;
+rsnd_dvc_probe_done:
+	of_node_put(node);
+
+	return ret;
 }
 
-void rsnd_dvc_remove(struct platform_device *pdev,
-		     struct rsnd_priv *priv)
+void rsnd_dvc_remove(struct rsnd_priv *priv)
 {
 	struct rsnd_dvc *dvc;
 	int i;
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index edcf4cc..ea24247 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -31,29 +31,33 @@
 
 	/* RSND_REG_MAX base */
 	struct regmap_field *regs[RSND_REG_MAX];
+	const char *reg_name[RSND_REG_MAX];
 };
 
 #define rsnd_priv_to_gen(p)	((struct rsnd_gen *)(p)->gen)
+#define rsnd_reg_name(gen, id)	((gen)->reg_name[id])
 
 struct rsnd_regmap_field_conf {
 	int idx;
 	unsigned int reg_offset;
 	unsigned int id_offset;
+	const char *reg_name;
 };
 
-#define RSND_REG_SET(id, offset, _id_offset)	\
+#define RSND_REG_SET(id, offset, _id_offset, n)	\
 {						\
 	.idx = id,				\
 	.reg_offset = offset,			\
 	.id_offset = _id_offset,		\
+	.reg_name = n,				\
 }
 /* single address mapping */
 #define RSND_GEN_S_REG(id, offset)	\
-	RSND_REG_SET(RSND_REG_##id, offset, 0)
+	RSND_REG_SET(RSND_REG_##id, offset, 0, #id)
 
 /* multi address mapping */
 #define RSND_GEN_M_REG(id, offset, _id_offset)	\
-	RSND_REG_SET(RSND_REG_##id, offset, _id_offset)
+	RSND_REG_SET(RSND_REG_##id, offset, _id_offset, #id)
 
 /*
  *		basic function
@@ -83,8 +87,9 @@
 
 	regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
 
-	dev_dbg(dev, "r %s[%d] - %4d : %08x\n",
-		rsnd_mod_name(mod), rsnd_mod_id(mod), reg, val);
+	dev_dbg(dev, "r %s[%d] - %-18s (%4d) : %08x\n",
+		rsnd_mod_name(mod), rsnd_mod_id(mod),
+		rsnd_reg_name(gen, reg), reg, val);
 
 	return val;
 }
@@ -99,10 +104,11 @@
 	if (!rsnd_is_accessible_reg(priv, gen, reg))
 		return;
 
-	dev_dbg(dev, "w %s[%d] - %4d : %08x\n",
-		rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data);
-
 	regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data);
+
+	dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n",
+		rsnd_mod_name(mod), rsnd_mod_id(mod),
+		rsnd_reg_name(gen, reg), reg, data);
 }
 
 void rsnd_force_write(struct rsnd_priv *priv,
@@ -115,10 +121,11 @@
 	if (!rsnd_is_accessible_reg(priv, gen, reg))
 		return;
 
-	dev_dbg(dev, "w %s[%d] - %4d : %08x\n",
-		rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data);
-
 	regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data);
+
+	dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n",
+		rsnd_mod_name(mod), rsnd_mod_id(mod),
+		rsnd_reg_name(gen, reg), reg, data);
 }
 
 void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
@@ -130,11 +137,13 @@
 	if (!rsnd_is_accessible_reg(priv, gen, reg))
 		return;
 
-	dev_dbg(dev, "b %s[%d] - %4d : %08x/%08x\n",
-		rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data, mask);
-
 	regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod),
 				  mask, data);
+
+	dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n",
+		rsnd_mod_name(mod), rsnd_mod_id(mod),
+		rsnd_reg_name(gen, reg), reg, data, mask);
+
 }
 
 phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id)
@@ -150,7 +159,7 @@
 				 int id_size,
 				 int reg_id,
 				 const char *name,
-				 struct rsnd_regmap_field_conf *conf,
+				 const struct rsnd_regmap_field_conf *conf,
 				 int conf_size)
 {
 	struct platform_device *pdev = rsnd_priv_to_pdev(priv);
@@ -203,6 +212,7 @@
 
 		/* RSND_REG_MAX base */
 		gen->regs[conf[i].idx] = regs;
+		gen->reg_name[conf[i].idx] = conf[i].reg_name;
 	}
 
 	return 0;
@@ -211,25 +221,31 @@
 /*
  *		Gen2
  */
-static int rsnd_gen2_probe(struct platform_device *pdev,
-			   struct rsnd_priv *priv)
+static int rsnd_gen2_probe(struct rsnd_priv *priv)
 {
-	struct rsnd_regmap_field_conf conf_ssiu[] = {
+	const static struct rsnd_regmap_field_conf conf_ssiu[] = {
 		RSND_GEN_S_REG(SSI_MODE0,	0x800),
 		RSND_GEN_S_REG(SSI_MODE1,	0x804),
+		RSND_GEN_S_REG(SSI_MODE2,	0x808),
+		RSND_GEN_S_REG(SSI_CONTROL,	0x810),
+
 		/* FIXME: it needs SSI_MODE2/3 in the future */
 		RSND_GEN_M_REG(SSI_BUSIF_MODE,	0x0,	0x80),
 		RSND_GEN_M_REG(SSI_BUSIF_ADINR,	0x4,	0x80),
 		RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8,	0x80),
+		RSND_GEN_M_REG(SSI_MODE,	0xc,	0x80),
 		RSND_GEN_M_REG(SSI_CTRL,	0x10,	0x80),
 		RSND_GEN_M_REG(SSI_INT_ENABLE,	0x18,	0x80),
 	};
-	struct rsnd_regmap_field_conf conf_scu[] = {
-		RSND_GEN_M_REG(SRC_BUSIF_MODE,	0x0,	0x20),
+
+	const static struct rsnd_regmap_field_conf conf_scu[] = {
+		RSND_GEN_M_REG(SRC_I_BUSIF_MODE,0x0,	0x20),
+		RSND_GEN_M_REG(SRC_O_BUSIF_MODE,0x4,	0x20),
 		RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8,	0x20),
 		RSND_GEN_M_REG(SRC_ROUTE_MODE0,	0xc,	0x20),
 		RSND_GEN_M_REG(SRC_CTRL,	0x10,	0x20),
 		RSND_GEN_M_REG(SRC_INT_ENABLE0,	0x18,	0x20),
+		RSND_GEN_M_REG(CMD_BUSIF_DALIGN,0x188,	0x20),
 		RSND_GEN_M_REG(CMD_ROUTE_SLCT,	0x18c,	0x20),
 		RSND_GEN_M_REG(CMD_CTRL,	0x190,	0x20),
 		RSND_GEN_S_REG(SCU_SYS_STATUS0,	0x1c8),
@@ -266,9 +282,15 @@
 		RSND_GEN_M_REG(DVC_VRDBR,	0xe20,	0x100),
 		RSND_GEN_M_REG(DVC_VOL0R,	0xe28,	0x100),
 		RSND_GEN_M_REG(DVC_VOL1R,	0xe2c,	0x100),
+		RSND_GEN_M_REG(DVC_VOL2R,	0xe30,	0x100),
+		RSND_GEN_M_REG(DVC_VOL3R,	0xe34,	0x100),
+		RSND_GEN_M_REG(DVC_VOL4R,	0xe38,	0x100),
+		RSND_GEN_M_REG(DVC_VOL5R,	0xe3c,	0x100),
+		RSND_GEN_M_REG(DVC_VOL6R,	0xe40,	0x100),
+		RSND_GEN_M_REG(DVC_VOL7R,	0xe44,	0x100),
 		RSND_GEN_M_REG(DVC_DVUER,	0xe48,	0x100),
 	};
-	struct rsnd_regmap_field_conf conf_adg[] = {
+	const static struct rsnd_regmap_field_conf conf_adg[] = {
 		RSND_GEN_S_REG(BRRA,		0x00),
 		RSND_GEN_S_REG(BRRB,		0x04),
 		RSND_GEN_S_REG(SSICKR,		0x08),
@@ -288,7 +310,7 @@
 		RSND_GEN_S_REG(SRCOUT_TIMSEL4,	0x58),
 		RSND_GEN_S_REG(CMDOUT_TIMSEL,	0x5c),
 	};
-	struct rsnd_regmap_field_conf conf_ssi[] = {
+	const static struct rsnd_regmap_field_conf conf_ssi[] = {
 		RSND_GEN_M_REG(SSICR,		0x00,	0x40),
 		RSND_GEN_M_REG(SSISR,		0x04,	0x40),
 		RSND_GEN_M_REG(SSITDR,		0x08,	0x40),
@@ -317,65 +339,30 @@
  *		Gen1
  */
 
-static int rsnd_gen1_probe(struct platform_device *pdev,
-			   struct rsnd_priv *priv)
+static int rsnd_gen1_probe(struct rsnd_priv *priv)
 {
-	struct rsnd_regmap_field_conf conf_sru[] = {
-		RSND_GEN_S_REG(SRC_ROUTE_SEL,	0x00),
-		RSND_GEN_S_REG(SRC_TMG_SEL0,	0x08),
-		RSND_GEN_S_REG(SRC_TMG_SEL1,	0x0c),
-		RSND_GEN_S_REG(SRC_TMG_SEL2,	0x10),
-		RSND_GEN_S_REG(SRC_ROUTE_CTRL,	0xc0),
-		RSND_GEN_S_REG(SSI_MODE0,	0xD0),
-		RSND_GEN_S_REG(SSI_MODE1,	0xD4),
-		RSND_GEN_M_REG(SRC_BUSIF_MODE,	0x20,	0x4),
-		RSND_GEN_M_REG(SRC_ROUTE_MODE0,	0x50,	0x8),
-		RSND_GEN_M_REG(SRC_SWRSR,	0x200,	0x40),
-		RSND_GEN_M_REG(SRC_SRCIR,	0x204,	0x40),
-		RSND_GEN_M_REG(SRC_ADINR,	0x214,	0x40),
-		RSND_GEN_M_REG(SRC_IFSCR,	0x21c,	0x40),
-		RSND_GEN_M_REG(SRC_IFSVR,	0x220,	0x40),
-		RSND_GEN_M_REG(SRC_SRCCR,	0x224,	0x40),
-		RSND_GEN_M_REG(SRC_MNFSR,	0x228,	0x40),
-		/*
-		 * ADD US
-		 *
-		 * SRC_STATUS
-		 * SRC_INT_EN
-		 * SCU_SYS_STATUS0
-		 * SCU_SYS_STATUS1
-		 * SCU_SYS_INT_EN0
-		 * SCU_SYS_INT_EN1
-		 */
-	};
-	struct rsnd_regmap_field_conf conf_adg[] = {
+	const static struct rsnd_regmap_field_conf conf_adg[] = {
 		RSND_GEN_S_REG(BRRA,		0x00),
 		RSND_GEN_S_REG(BRRB,		0x04),
 		RSND_GEN_S_REG(SSICKR,		0x08),
 		RSND_GEN_S_REG(AUDIO_CLK_SEL0,	0x0c),
 		RSND_GEN_S_REG(AUDIO_CLK_SEL1,	0x10),
-		RSND_GEN_S_REG(AUDIO_CLK_SEL3,	0x18),
-		RSND_GEN_S_REG(AUDIO_CLK_SEL4,	0x1c),
-		RSND_GEN_S_REG(AUDIO_CLK_SEL5,	0x20),
 	};
-	struct rsnd_regmap_field_conf conf_ssi[] = {
+	const static struct rsnd_regmap_field_conf conf_ssi[] = {
 		RSND_GEN_M_REG(SSICR,		0x00,	0x40),
 		RSND_GEN_M_REG(SSISR,		0x04,	0x40),
 		RSND_GEN_M_REG(SSITDR,		0x08,	0x40),
 		RSND_GEN_M_REG(SSIRDR,		0x0c,	0x40),
 		RSND_GEN_M_REG(SSIWSR,		0x20,	0x40),
 	};
-	int ret_sru;
 	int ret_adg;
 	int ret_ssi;
 
-	ret_sru  = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU, "sru", conf_sru);
 	ret_adg  = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg);
 	ret_ssi  = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi);
-	if (ret_sru  < 0 ||
-	    ret_adg  < 0 ||
+	if (ret_adg  < 0 ||
 	    ret_ssi  < 0)
-		return ret_sru | ret_adg | ret_ssi;
+		return ret_adg | ret_ssi;
 
 	return 0;
 }
@@ -383,28 +370,12 @@
 /*
  *		Gen
  */
-static void rsnd_of_parse_gen(struct platform_device *pdev,
-			      const struct rsnd_of_data *of_data,
-			      struct rsnd_priv *priv)
-{
-	struct rcar_snd_info *info = priv->info;
-
-	if (!of_data)
-		return;
-
-	info->flags = of_data->flags;
-}
-
-int rsnd_gen_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv)
+int rsnd_gen_probe(struct rsnd_priv *priv)
 {
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_gen *gen;
 	int ret;
 
-	rsnd_of_parse_gen(pdev, of_data, priv);
-
 	gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
 	if (!gen) {
 		dev_err(dev, "GEN allocate failed\n");
@@ -415,9 +386,9 @@
 
 	ret = -ENODEV;
 	if (rsnd_is_gen1(priv))
-		ret = rsnd_gen1_probe(pdev, priv);
+		ret = rsnd_gen1_probe(priv);
 	else if (rsnd_is_gen2(priv))
-		ret = rsnd_gen2_probe(pdev, priv);
+		ret = rsnd_gen2_probe(priv);
 
 	if (ret < 0)
 		dev_err(dev, "unknown generation R-Car sound device\n");
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c
index 953dd0b..65542b6 100644
--- a/sound/soc/sh/rcar/mix.c
+++ b/sound/soc/sh/rcar/mix.c
@@ -13,10 +13,10 @@
 #define MIX_NAME "mix"
 
 struct rsnd_mix {
-	struct rsnd_mix_platform_info *info; /* rcar_snd.h */
 	struct rsnd_mod mod;
 };
 
+#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id)
 #define rsnd_mix_nr(priv) ((priv)->mix_nr)
 #define for_each_rsnd_mix(pos, priv, i)					\
 	for ((i) = 0;							\
@@ -24,58 +24,77 @@
 		     ((pos) = (struct rsnd_mix *)(priv)->mix + i);	\
 	     i++)
 
-
-static void rsnd_mix_soft_reset(struct rsnd_mod *mod)
+static void rsnd_mix_activation(struct rsnd_mod *mod)
 {
 	rsnd_mod_write(mod, MIX_SWRSR, 0);
 	rsnd_mod_write(mod, MIX_SWRSR, 1);
 }
 
-#define rsnd_mix_initialize_lock(mod)	__rsnd_mix_initialize_lock(mod, 1)
-#define rsnd_mix_initialize_unlock(mod)	__rsnd_mix_initialize_lock(mod, 0)
-static void __rsnd_mix_initialize_lock(struct rsnd_mod *mod, u32 enable)
+static void rsnd_mix_halt(struct rsnd_mod *mod)
 {
-	rsnd_mod_write(mod, MIX_MIXIR, enable);
+	rsnd_mod_write(mod, MIX_MIXIR, 1);
+	rsnd_mod_write(mod, MIX_SWRSR, 0);
+}
+
+static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io,
+				      struct rsnd_mod *mod)
+{
+	rsnd_mod_write(mod, MIX_MDBAR, 0);
+	rsnd_mod_write(mod, MIX_MDBBR, 0);
+	rsnd_mod_write(mod, MIX_MDBCR, 0);
+	rsnd_mod_write(mod, MIX_MDBDR, 0);
+}
+
+static void rsnd_mix_volume_init(struct rsnd_dai_stream *io,
+				 struct rsnd_mod *mod)
+{
+	rsnd_mod_write(mod, MIX_MIXIR, 1);
+
+	/* General Information */
+	rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io));
+
+	/* volume step */
+	rsnd_mod_write(mod, MIX_MIXMR, 0);
+	rsnd_mod_write(mod, MIX_MVPDR, 0);
+
+	/* common volume parameter */
+	rsnd_mix_volume_parameter(io, mod);
+
+	rsnd_mod_write(mod, MIX_MIXIR, 0);
 }
 
 static void rsnd_mix_volume_update(struct rsnd_dai_stream *io,
 				  struct rsnd_mod *mod)
 {
-
 	/* Disable MIX dB setting */
 	rsnd_mod_write(mod, MIX_MDBER, 0);
 
-	rsnd_mod_write(mod, MIX_MDBAR, 0);
-	rsnd_mod_write(mod, MIX_MDBBR, 0);
-	rsnd_mod_write(mod, MIX_MDBCR, 0);
-	rsnd_mod_write(mod, MIX_MDBDR, 0);
+	/* common volume parameter */
+	rsnd_mix_volume_parameter(io, mod);
 
 	/* Enable MIX dB setting */
 	rsnd_mod_write(mod, MIX_MDBER, 1);
 }
 
+static int rsnd_mix_probe_(struct rsnd_mod *mod,
+			   struct rsnd_dai_stream *io,
+			   struct rsnd_priv *priv)
+{
+	return rsnd_cmd_attach(io, rsnd_mod_id(mod));
+}
+
 static int rsnd_mix_init(struct rsnd_mod *mod,
 			 struct rsnd_dai_stream *io,
 			 struct rsnd_priv *priv)
 {
 	rsnd_mod_power_on(mod);
 
-	rsnd_mix_soft_reset(mod);
+	rsnd_mix_activation(mod);
 
-	rsnd_mix_initialize_lock(mod);
-
-	rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io));
-
-	rsnd_path_parse(priv, io);
-
-	/* volume step */
-	rsnd_mod_write(mod, MIX_MIXMR, 0);
-	rsnd_mod_write(mod, MIX_MVPDR, 0);
+	rsnd_mix_volume_init(io, mod);
 
 	rsnd_mix_volume_update(io, mod);
 
-	rsnd_mix_initialize_unlock(mod);
-
 	return 0;
 }
 
@@ -83,6 +102,8 @@
 			 struct rsnd_dai_stream *io,
 			 struct rsnd_priv *priv)
 {
+	rsnd_mix_halt(mod);
+
 	rsnd_mod_power_off(mod);
 
 	return 0;
@@ -90,6 +111,7 @@
 
 static struct rsnd_mod_ops rsnd_mix_ops = {
 	.name		= MIX_NAME,
+	.probe		= rsnd_mix_probe_,
 	.init		= rsnd_mix_init,
 	.quit		= rsnd_mix_quit,
 };
@@ -99,51 +121,13 @@
 	if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv)))
 		id = 0;
 
-	return rsnd_mod_get((struct rsnd_mix *)(priv->mix) + id);
+	return rsnd_mod_get(rsnd_mix_get(priv, id));
 }
 
-static void rsnd_of_parse_mix(struct platform_device *pdev,
-			      const struct rsnd_of_data *of_data,
-			      struct rsnd_priv *priv)
+int rsnd_mix_probe(struct rsnd_priv *priv)
 {
 	struct device_node *node;
-	struct rsnd_mix_platform_info *mix_info;
-	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-	struct device *dev = &pdev->dev;
-	int nr;
-
-	if (!of_data)
-		return;
-
-	node = of_get_child_by_name(dev->of_node, "rcar_sound,mix");
-	if (!node)
-		return;
-
-	nr = of_get_child_count(node);
-	if (!nr)
-		goto rsnd_of_parse_mix_end;
-
-	mix_info = devm_kzalloc(dev,
-				sizeof(struct rsnd_mix_platform_info) * nr,
-				GFP_KERNEL);
-	if (!mix_info) {
-		dev_err(dev, "mix info allocation error\n");
-		goto rsnd_of_parse_mix_end;
-	}
-
-	info->mix_info		= mix_info;
-	info->mix_info_nr	= nr;
-
-rsnd_of_parse_mix_end:
-	of_node_put(node);
-
-}
-
-int rsnd_mix_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv)
-{
-	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+	struct device_node *np;
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_mix *mix;
 	struct clk *clk;
@@ -154,40 +138,54 @@
 	if (rsnd_is_gen1(priv))
 		return 0;
 
-	rsnd_of_parse_mix(pdev, of_data, priv);
+	node = rsnd_mix_of_node(priv);
+	if (!node)
+		return 0; /* not used is not error */
 
-	nr = info->mix_info_nr;
-	if (!nr)
-		return 0;
+	nr = of_get_child_count(node);
+	if (!nr) {
+		ret = -EINVAL;
+		goto rsnd_mix_probe_done;
+	}
 
 	mix	= devm_kzalloc(dev, sizeof(*mix) * nr, GFP_KERNEL);
-	if (!mix)
-		return -ENOMEM;
+	if (!mix) {
+		ret = -ENOMEM;
+		goto rsnd_mix_probe_done;
+	}
 
 	priv->mix_nr	= nr;
 	priv->mix	= mix;
 
-	for_each_rsnd_mix(mix, priv, i) {
+	i = 0;
+	ret = 0;
+	for_each_child_of_node(node, np) {
+		mix = rsnd_mix_get(priv, i);
+
 		snprintf(name, MIX_NAME_SIZE, "%s.%d",
 			 MIX_NAME, i);
 
 		clk = devm_clk_get(dev, name);
-		if (IS_ERR(clk))
-			return PTR_ERR(clk);
-
-		mix->info = &info->mix_info[i];
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			goto rsnd_mix_probe_done;
+		}
 
 		ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
 				    clk, RSND_MOD_MIX, i);
 		if (ret)
-			return ret;
+			goto rsnd_mix_probe_done;
+
+		i++;
 	}
 
-	return 0;
+rsnd_mix_probe_done:
+	of_node_put(node);
+
+	return ret;
 }
 
-void rsnd_mix_remove(struct platform_device *pdev,
-		     struct rsnd_priv *priv)
+void rsnd_mix_remove(struct rsnd_priv *priv)
 {
 	struct rsnd_mix *mix;
 	int i;
diff --git a/sound/soc/sh/rcar/rcar_snd.h b/sound/soc/sh/rcar/rcar_snd.h
deleted file mode 100644
index d8e33d3..0000000
--- a/sound/soc/sh/rcar/rcar_snd.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Renesas R-Car SRU/SCU/SSIU/SSI support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 RCAR_SND_H
-#define RCAR_SND_H
-
-
-#define RSND_GEN1_SRU	0
-#define RSND_GEN1_ADG	1
-#define RSND_GEN1_SSI	2
-
-#define RSND_GEN2_SCU	0
-#define RSND_GEN2_ADG	1
-#define RSND_GEN2_SSIU	2
-#define RSND_GEN2_SSI	3
-
-#define RSND_BASE_MAX	4
-
-/*
- * flags
- *
- * 0xAB000000
- *
- * A : clock sharing settings
- * B : SSI direction
- */
-#define RSND_SSI_CLK_PIN_SHARE		(1 << 31)
-#define RSND_SSI_NO_BUSIF		(1 << 30) /* SSI+DMA without BUSIF */
-
-#define RSND_SSI(_dma_id, _irq, _flags)		\
-{ .dma_id = _dma_id, .irq = _irq, .flags = _flags }
-#define RSND_SSI_UNUSED \
-{ .dma_id = -1, .irq = -1, .flags = 0 }
-
-struct rsnd_ssi_platform_info {
-	int dma_id;
-	int irq;
-	u32 flags;
-};
-
-#define RSND_SRC(rate, _dma_id)						\
-{ .convert_rate = rate, .dma_id = _dma_id, }
-#define RSND_SRC_UNUSED				\
-{ .convert_rate = 0, .dma_id = -1, }
-
-struct rsnd_src_platform_info {
-	u32 convert_rate; /* sampling rate convert */
-	int dma_id; /* for Gen2 SCU */
-	int irq;
-};
-
-/*
- * flags
- */
-struct rsnd_ctu_platform_info {
-	u32 flags;
-};
-
-struct rsnd_mix_platform_info {
-	u32 flags;
-};
-
-struct rsnd_dvc_platform_info {
-	u32 flags;
-};
-
-struct rsnd_dai_path_info {
-	struct rsnd_ssi_platform_info *ssi;
-	struct rsnd_src_platform_info *src;
-	struct rsnd_ctu_platform_info *ctu;
-	struct rsnd_mix_platform_info *mix;
-	struct rsnd_dvc_platform_info *dvc;
-};
-
-struct rsnd_dai_platform_info {
-	struct rsnd_dai_path_info playback;
-	struct rsnd_dai_path_info capture;
-};
-
-/*
- * flags
- *
- * 0x0000000A
- *
- * A : generation
- */
-#define RSND_GEN_MASK	(0xF << 0)
-#define RSND_GEN1	(1 << 0) /* fixme */
-#define RSND_GEN2	(2 << 0) /* fixme */
-
-struct rcar_snd_info {
-	u32 flags;
-	struct rsnd_ssi_platform_info *ssi_info;
-	int ssi_info_nr;
-	struct rsnd_src_platform_info *src_info;
-	int src_info_nr;
-	struct rsnd_ctu_platform_info *ctu_info;
-	int ctu_info_nr;
-	struct rsnd_mix_platform_info *mix_info;
-	int mix_info_nr;
-	struct rsnd_dvc_platform_info *dvc_info;
-	int dvc_info_nr;
-	struct rsnd_dai_platform_info *dai_info;
-	int dai_info_nr;
-	int (*start)(int id);
-	int (*stop)(int id);
-};
-
-#endif
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 0853298..317dd79 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -24,7 +24,16 @@
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
 
-#include "rcar_snd.h"
+#define RSND_GEN1_SRU	0
+#define RSND_GEN1_ADG	1
+#define RSND_GEN1_SSI	2
+
+#define RSND_GEN2_SCU	0
+#define RSND_GEN2_ADG	1
+#define RSND_GEN2_SSIU	2
+#define RSND_GEN2_SSI	3
+
+#define RSND_BASE_MAX	4
 
 /*
  *	pseudo register
@@ -34,10 +43,19 @@
  * see gen1/gen2 for detail
  */
 enum rsnd_reg {
-	/* SRU/SCU/SSIU */
+	/* SCU (SRC/SSIU/MIX/CTU/DVC) */
+	RSND_REG_SSI_MODE,		/* Gen2 only */
 	RSND_REG_SSI_MODE0,
 	RSND_REG_SSI_MODE1,
-	RSND_REG_SRC_BUSIF_MODE,
+	RSND_REG_SSI_MODE2,
+	RSND_REG_SSI_CONTROL,
+	RSND_REG_SSI_CTRL,		/* Gen2 only */
+	RSND_REG_SSI_BUSIF_MODE,	/* Gen2 only */
+	RSND_REG_SSI_BUSIF_ADINR,	/* Gen2 only */
+	RSND_REG_SSI_BUSIF_DALIGN,	/* Gen2 only */
+	RSND_REG_SSI_INT_ENABLE,	/* Gen2 only */
+	RSND_REG_SRC_I_BUSIF_MODE,
+	RSND_REG_SRC_O_BUSIF_MODE,
 	RSND_REG_SRC_ROUTE_MODE0,
 	RSND_REG_SRC_SWRSR,
 	RSND_REG_SRC_SRCIR,
@@ -45,9 +63,29 @@
 	RSND_REG_SRC_IFSCR,
 	RSND_REG_SRC_IFSVR,
 	RSND_REG_SRC_SRCCR,
+	RSND_REG_SRC_CTRL,		/* Gen2 only */
+	RSND_REG_SRC_BSDSR,		/* Gen2 only */
+	RSND_REG_SRC_BSISR,		/* Gen2 only */
+	RSND_REG_SRC_INT_ENABLE0,	/* Gen2 only */
+	RSND_REG_SRC_BUSIF_DALIGN,	/* Gen2 only */
+	RSND_REG_SRCIN_TIMSEL0,		/* Gen2 only */
+	RSND_REG_SRCIN_TIMSEL1,		/* Gen2 only */
+	RSND_REG_SRCIN_TIMSEL2,		/* Gen2 only */
+	RSND_REG_SRCIN_TIMSEL3,		/* Gen2 only */
+	RSND_REG_SRCIN_TIMSEL4,		/* Gen2 only */
+	RSND_REG_SRCOUT_TIMSEL0,	/* Gen2 only */
+	RSND_REG_SRCOUT_TIMSEL1,	/* Gen2 only */
+	RSND_REG_SRCOUT_TIMSEL2,	/* Gen2 only */
+	RSND_REG_SRCOUT_TIMSEL3,	/* Gen2 only */
+	RSND_REG_SRCOUT_TIMSEL4,	/* Gen2 only */
 	RSND_REG_SCU_SYS_STATUS0,
+	RSND_REG_SCU_SYS_STATUS1,	/* Gen2 only */
 	RSND_REG_SCU_SYS_INT_EN0,
+	RSND_REG_SCU_SYS_INT_EN1,	/* Gen2 only */
+	RSND_REG_CMD_CTRL,		/* Gen2 only */
+	RSND_REG_CMD_BUSIF_DALIGN,	/* Gen2 only */
 	RSND_REG_CMD_ROUTE_SLCT,
+	RSND_REG_CMDOUT_TIMSEL,		/* Gen2 only */
 	RSND_REG_CTU_CTUIR,
 	RSND_REG_CTU_ADINR,
 	RSND_REG_MIX_SWRSR,
@@ -67,14 +105,25 @@
 	RSND_REG_DVC_ZCMCR,
 	RSND_REG_DVC_VOL0R,
 	RSND_REG_DVC_VOL1R,
+	RSND_REG_DVC_VOL2R,
+	RSND_REG_DVC_VOL3R,
+	RSND_REG_DVC_VOL4R,
+	RSND_REG_DVC_VOL5R,
+	RSND_REG_DVC_VOL6R,
+	RSND_REG_DVC_VOL7R,
 	RSND_REG_DVC_DVUER,
+	RSND_REG_DVC_VRCTR,		/* Gen2 only */
+	RSND_REG_DVC_VRPDR,		/* Gen2 only */
+	RSND_REG_DVC_VRDBR,		/* Gen2 only */
 
 	/* ADG */
 	RSND_REG_BRRA,
 	RSND_REG_BRRB,
 	RSND_REG_SSICKR,
+	RSND_REG_DIV_EN,		/* Gen2 only */
 	RSND_REG_AUDIO_CLK_SEL0,
 	RSND_REG_AUDIO_CLK_SEL1,
+	RSND_REG_AUDIO_CLK_SEL2,	/* Gen2 only */
 
 	/* SSI */
 	RSND_REG_SSICR,
@@ -83,83 +132,9 @@
 	RSND_REG_SSIRDR,
 	RSND_REG_SSIWSR,
 
-	/* SHARE see below */
-	RSND_REG_SHARE01,
-	RSND_REG_SHARE02,
-	RSND_REG_SHARE03,
-	RSND_REG_SHARE04,
-	RSND_REG_SHARE05,
-	RSND_REG_SHARE06,
-	RSND_REG_SHARE07,
-	RSND_REG_SHARE08,
-	RSND_REG_SHARE09,
-	RSND_REG_SHARE10,
-	RSND_REG_SHARE11,
-	RSND_REG_SHARE12,
-	RSND_REG_SHARE13,
-	RSND_REG_SHARE14,
-	RSND_REG_SHARE15,
-	RSND_REG_SHARE16,
-	RSND_REG_SHARE17,
-	RSND_REG_SHARE18,
-	RSND_REG_SHARE19,
-	RSND_REG_SHARE20,
-	RSND_REG_SHARE21,
-	RSND_REG_SHARE22,
-	RSND_REG_SHARE23,
-	RSND_REG_SHARE24,
-	RSND_REG_SHARE25,
-	RSND_REG_SHARE26,
-	RSND_REG_SHARE27,
-	RSND_REG_SHARE28,
-	RSND_REG_SHARE29,
-
 	RSND_REG_MAX,
 };
 
-/* Gen1 only */
-#define RSND_REG_SRC_ROUTE_SEL		RSND_REG_SHARE01
-#define RSND_REG_SRC_TMG_SEL0		RSND_REG_SHARE02
-#define RSND_REG_SRC_TMG_SEL1		RSND_REG_SHARE03
-#define RSND_REG_SRC_TMG_SEL2		RSND_REG_SHARE04
-#define RSND_REG_SRC_ROUTE_CTRL		RSND_REG_SHARE05
-#define RSND_REG_SRC_MNFSR		RSND_REG_SHARE06
-#define RSND_REG_AUDIO_CLK_SEL3		RSND_REG_SHARE07
-#define RSND_REG_AUDIO_CLK_SEL4		RSND_REG_SHARE08
-#define RSND_REG_AUDIO_CLK_SEL5		RSND_REG_SHARE09
-
-/* Gen2 only */
-#define RSND_REG_SRC_CTRL		RSND_REG_SHARE01
-#define RSND_REG_SSI_CTRL		RSND_REG_SHARE02
-#define RSND_REG_SSI_BUSIF_MODE		RSND_REG_SHARE03
-#define RSND_REG_SSI_BUSIF_ADINR	RSND_REG_SHARE04
-#define RSND_REG_SSI_INT_ENABLE		RSND_REG_SHARE05
-#define RSND_REG_SRC_BSDSR		RSND_REG_SHARE06
-#define RSND_REG_SRC_BSISR		RSND_REG_SHARE07
-#define RSND_REG_DIV_EN			RSND_REG_SHARE08
-#define RSND_REG_SRCIN_TIMSEL0		RSND_REG_SHARE09
-#define RSND_REG_SRCIN_TIMSEL1		RSND_REG_SHARE10
-#define RSND_REG_SRCIN_TIMSEL2		RSND_REG_SHARE11
-#define RSND_REG_SRCIN_TIMSEL3		RSND_REG_SHARE12
-#define RSND_REG_SRCIN_TIMSEL4		RSND_REG_SHARE13
-#define RSND_REG_SRCOUT_TIMSEL0		RSND_REG_SHARE14
-#define RSND_REG_SRCOUT_TIMSEL1		RSND_REG_SHARE15
-#define RSND_REG_SRCOUT_TIMSEL2		RSND_REG_SHARE16
-#define RSND_REG_SRCOUT_TIMSEL3		RSND_REG_SHARE17
-#define RSND_REG_SRCOUT_TIMSEL4		RSND_REG_SHARE18
-#define RSND_REG_AUDIO_CLK_SEL2		RSND_REG_SHARE19
-#define RSND_REG_CMD_CTRL		RSND_REG_SHARE20
-#define RSND_REG_CMDOUT_TIMSEL		RSND_REG_SHARE21
-#define RSND_REG_SSI_BUSIF_DALIGN	RSND_REG_SHARE22
-#define RSND_REG_DVC_VRCTR		RSND_REG_SHARE23
-#define RSND_REG_DVC_VRPDR		RSND_REG_SHARE24
-#define RSND_REG_DVC_VRDBR		RSND_REG_SHARE25
-#define RSND_REG_SCU_SYS_STATUS1	RSND_REG_SHARE26
-#define RSND_REG_SCU_SYS_INT_EN1	RSND_REG_SHARE27
-#define RSND_REG_SRC_INT_ENABLE0	RSND_REG_SHARE28
-#define RSND_REG_SRC_BUSIF_DALIGN	RSND_REG_SHARE29
-
-struct rsnd_of_data;
 struct rsnd_priv;
 struct rsnd_mod;
 struct rsnd_dai;
@@ -187,43 +162,13 @@
 u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
 u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
 u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
-void rsnd_path_parse(struct rsnd_priv *priv,
-		     struct rsnd_dai_stream *io);
 
 /*
  *	R-Car DMA
  */
-struct rsnd_dma;
-
-struct rsnd_dmaen {
-	struct dma_chan		*chan;
-};
-
-struct rsnd_dmapp {
-	int			dmapp_id;
-	u32			chcr;
-};
-
-struct rsnd_dma {
-	struct rsnd_dma_ops	*ops;
-	dma_addr_t		src_addr;
-	dma_addr_t		dst_addr;
-	union {
-		struct rsnd_dmaen en;
-		struct rsnd_dmapp pp;
-	} dma;
-};
-#define rsnd_dma_to_dmaen(dma)	(&(dma)->dma.en)
-#define rsnd_dma_to_dmapp(dma)	(&(dma)->dma.pp)
-#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
-
-void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id);
-void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-int rsnd_dma_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io,
+			       struct rsnd_mod *mod, int id);
+int rsnd_dma_probe(struct rsnd_priv *priv);
 struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
 					  struct rsnd_mod *mod, char *name);
 
@@ -231,11 +176,19 @@
  *	R-Car sound mod
  */
 enum rsnd_mod_type {
-	RSND_MOD_DVC = 0,
+	RSND_MOD_AUDMAPP,
+	RSND_MOD_AUDMA,
+	RSND_MOD_DVC,
 	RSND_MOD_MIX,
 	RSND_MOD_CTU,
+	RSND_MOD_CMD,
 	RSND_MOD_SRC,
+	RSND_MOD_SSIM3,		/* SSI multi 3 */
+	RSND_MOD_SSIM2,		/* SSI multi 2 */
+	RSND_MOD_SSIM1,		/* SSI multi 1 */
+	RSND_MOD_SSIP,		/* SSI parent */
 	RSND_MOD_SSI,
+	RSND_MOD_SSIU,
 	RSND_MOD_MAX,
 };
 
@@ -278,10 +231,8 @@
 	int id;
 	enum rsnd_mod_type type;
 	struct rsnd_mod_ops *ops;
-	struct rsnd_dma dma;
 	struct rsnd_priv *priv;
 	struct clk *clk;
-	u32 status;
 };
 /*
  * status
@@ -328,7 +279,6 @@
 #define __rsnd_mod_call_hw_params	0
 
 #define rsnd_mod_to_priv(mod) ((mod)->priv)
-#define rsnd_mod_to_dma(mod) (&(mod)->dma)
 #define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1)
 #define rsnd_mod_power_on(mod)	clk_enable((mod)->clk)
 #define rsnd_mod_power_off(mod)	clk_disable((mod)->clk)
@@ -347,6 +297,17 @@
 void rsnd_mod_interrupt(struct rsnd_mod *mod,
 			void (*callback)(struct rsnd_mod *mod,
 					 struct rsnd_dai_stream *io));
+void rsnd_parse_connect_common(struct rsnd_dai *rdai,
+		struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
+		struct device_node *node,
+		struct device_node *playback,
+		struct device_node *capture);
+
+void rsnd_set_slot(struct rsnd_dai *rdai,
+		   int slots, int slots_total);
+int rsnd_get_slot(struct rsnd_dai_stream *io);
+int rsnd_get_slot_width(struct rsnd_dai_stream *io);
+int rsnd_get_slot_num(struct rsnd_dai_stream *io);
 
 /*
  *	R-Car sound DAI
@@ -358,6 +319,7 @@
 	struct rsnd_mod *mod[RSND_MOD_MAX];
 	struct rsnd_dai_path_info *info; /* rcar_snd.h */
 	struct rsnd_dai *rdai;
+	u32 mod_status[RSND_MOD_MAX];
 	int byte_pos;
 	int period_pos;
 	int byte_per_period;
@@ -365,10 +327,12 @@
 };
 #define rsnd_io_to_mod(io, i)	((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
 #define rsnd_io_to_mod_ssi(io)	rsnd_io_to_mod((io), RSND_MOD_SSI)
+#define rsnd_io_to_mod_ssip(io)	rsnd_io_to_mod((io), RSND_MOD_SSIP)
 #define rsnd_io_to_mod_src(io)	rsnd_io_to_mod((io), RSND_MOD_SRC)
 #define rsnd_io_to_mod_ctu(io)	rsnd_io_to_mod((io), RSND_MOD_CTU)
 #define rsnd_io_to_mod_mix(io)	rsnd_io_to_mod((io), RSND_MOD_MIX)
 #define rsnd_io_to_mod_dvc(io)	rsnd_io_to_mod((io), RSND_MOD_DVC)
+#define rsnd_io_to_mod_cmd(io)	rsnd_io_to_mod((io), RSND_MOD_CMD)
 #define rsnd_io_to_rdai(io)	((io)->rdai)
 #define rsnd_io_to_priv(io)	(rsnd_rdai_to_priv(rsnd_io_to_rdai(io)))
 #define rsnd_io_is_play(io)	(&rsnd_io_to_rdai(io)->playback == io)
@@ -382,6 +346,9 @@
 	struct rsnd_dai_stream capture;
 	struct rsnd_priv *priv;
 
+	int slots;
+	int slots_num;
+
 	unsigned int clk_master:1;
 	unsigned int bit_clk_inv:1;
 	unsigned int frm_clk_inv:1;
@@ -403,33 +370,28 @@
 bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
 void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io);
 int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
+int rsnd_dai_connect(struct rsnd_mod *mod,
+		     struct rsnd_dai_stream *io,
+		     enum rsnd_mod_type type);
+#define rsnd_dai_of_node(priv)						\
+	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dai")
 
 /*
  *	R-Car Gen1/Gen2
  */
-int rsnd_gen_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv);
+int rsnd_gen_probe(struct rsnd_priv *priv);
 void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
 			       struct rsnd_mod *mod,
 			       enum rsnd_reg reg);
 phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id);
 
-#define rsnd_is_gen1(s)		(((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1)
-#define rsnd_is_gen2(s)		(((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2)
-
 /*
  *	R-Car ADG
  */
 int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod);
 int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
-int rsnd_adg_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv);
-int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
-				  struct rsnd_mod *mod,
-				  unsigned int src_rate,
-				  unsigned int dst_rate);
+int rsnd_adg_probe(struct rsnd_priv *priv);
+void rsnd_adg_remove(struct rsnd_priv *priv);
 int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
 				  struct rsnd_dai_stream *io,
 				  unsigned int src_rate,
@@ -442,15 +404,14 @@
 /*
  *	R-Car sound priv
  */
-struct rsnd_of_data {
-	u32 flags;
-};
-
 struct rsnd_priv {
 
 	struct platform_device *pdev;
-	struct rcar_snd_info *info;
 	spinlock_t lock;
+	unsigned long flags;
+#define RSND_GEN_MASK	(0xF << 0)
+#define RSND_GEN1	(1 << 0)
+#define RSND_GEN2	(2 << 0)
 
 	/*
 	 * below value will be filled on rsnd_gen_probe()
@@ -474,6 +435,12 @@
 	int ssi_nr;
 
 	/*
+	 * below value will be filled on rsnd_ssiu_probe()
+	 */
+	void *ssiu;
+	int ssiu_nr;
+
+	/*
 	 * below value will be filled on rsnd_src_probe()
 	 */
 	void *src;
@@ -498,6 +465,12 @@
 	int dvc_nr;
 
 	/*
+	 * below value will be filled on rsnd_cmd_probe()
+	 */
+	void *cmd;
+	int cmd_nr;
+
+	/*
 	 * below value will be filled on rsnd_dai_probe()
 	 */
 	struct snd_soc_dai_driver *daidrv;
@@ -507,7 +480,9 @@
 
 #define rsnd_priv_to_pdev(priv)	((priv)->pdev)
 #define rsnd_priv_to_dev(priv)	(&(rsnd_priv_to_pdev(priv)->dev))
-#define rsnd_priv_to_info(priv)	((priv)->info)
+
+#define rsnd_is_gen1(priv)	(((priv)->flags & RSND_GEN_MASK) == RSND_GEN1)
+#define rsnd_is_gen2(priv)	(((priv)->flags & RSND_GEN_MASK) == RSND_GEN2)
 
 /*
  *	rsnd_kctrl
@@ -523,7 +498,7 @@
 	struct snd_kcontrol *kctrl;
 };
 
-#define RSND_DVC_CHANNELS	2
+#define RSND_DVC_CHANNELS	8
 struct rsnd_kctrl_cfg_m {
 	struct rsnd_kctrl_cfg cfg;
 	u32 val[RSND_DVC_CHANNELS];
@@ -544,6 +519,7 @@
 		     void (*update)(struct rsnd_dai_stream *io,
 				    struct rsnd_mod *mod),
 		     struct rsnd_kctrl_cfg_m *_cfg,
+		     int ch_size,
 		     u32 max);
 int rsnd_kctrl_new_s(struct rsnd_mod *mod,
 		     struct rsnd_dai_stream *io,
@@ -566,70 +542,93 @@
 /*
  *	R-Car SSI
  */
-int rsnd_ssi_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv);
-void rsnd_ssi_remove(struct platform_device *pdev,
-		     struct rsnd_priv *priv);
+int rsnd_ssi_probe(struct rsnd_priv *priv);
+void rsnd_ssi_remove(struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
 int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
 int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
+u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io);
 
 #define rsnd_ssi_is_pin_sharing(io)	\
 	__rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
 int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
 
+#define rsnd_ssi_of_node(priv)						\
+	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
+void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
+			    struct device_node *playback,
+			    struct device_node *capture);
+
+/*
+ *	R-Car SSIU
+ */
+int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
+		     struct rsnd_mod *mod);
+int rsnd_ssiu_probe(struct rsnd_priv *priv);
+void rsnd_ssiu_remove(struct rsnd_priv *priv);
+
 /*
  *	R-Car SRC
  */
-int rsnd_src_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv);
-void rsnd_src_remove(struct platform_device *pdev,
-		     struct rsnd_priv *priv);
+int rsnd_src_probe(struct rsnd_priv *priv);
+void rsnd_src_remove(struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
 unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
 				   struct rsnd_dai_stream *io,
 				   struct snd_pcm_runtime *runtime);
-int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
-			struct rsnd_dai_stream *io,
-			int use_busif);
-int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
-		       struct rsnd_dai_stream *io);
-int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod);
-int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod);
+#define rsnd_src_of_node(priv)						\
+	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
+#define rsnd_parse_connect_src(rdai, playback, capture)			\
+	rsnd_parse_connect_common(rdai, rsnd_src_mod_get,		\
+				  rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \
+						   playback, capture)
 
 /*
  *	R-Car CTU
  */
-int rsnd_ctu_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv);
-
-void rsnd_ctu_remove(struct platform_device *pdev,
-		     struct rsnd_priv *priv);
+int rsnd_ctu_probe(struct rsnd_priv *priv);
+void rsnd_ctu_remove(struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
+#define rsnd_ctu_of_node(priv)						\
+	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu")
+#define rsnd_parse_connect_ctu(rdai, playback, capture)			\
+	rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get,		\
+				  rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \
+						   playback, capture)
 
 /*
  *	R-Car MIX
  */
-int rsnd_mix_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv);
-
-void rsnd_mix_remove(struct platform_device *pdev,
-		     struct rsnd_priv *priv);
+int rsnd_mix_probe(struct rsnd_priv *priv);
+void rsnd_mix_remove(struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
+#define rsnd_mix_of_node(priv)						\
+	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix")
+#define rsnd_parse_connect_mix(rdai, playback, capture)			\
+	rsnd_parse_connect_common(rdai, rsnd_mix_mod_get,		\
+				  rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \
+						   playback, capture)
 
 /*
  *	R-Car DVC
  */
-int rsnd_dvc_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv);
-void rsnd_dvc_remove(struct platform_device *pdev,
-		     struct rsnd_priv *priv);
+int rsnd_dvc_probe(struct rsnd_priv *priv);
+void rsnd_dvc_remove(struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
+#define rsnd_dvc_of_node(priv)						\
+	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
+#define rsnd_parse_connect_dvc(rdai, playback, capture)			\
+	rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get,		\
+				  rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \
+						   playback, capture)
+
+/*
+ *	R-Car CMD
+ */
+int rsnd_cmd_probe(struct rsnd_priv *priv);
+void rsnd_cmd_remove(struct rsnd_priv *priv);
+int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id);
+struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id);
 
 #ifdef DEBUG
 void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c
index d61db9c..8a357fd 100644
--- a/sound/soc/sh/rcar/rsrc-card.c
+++ b/sound/soc/sh/rcar/rsrc-card.c
@@ -48,8 +48,11 @@
 
 #define DAI_NAME_NUM	32
 struct rsrc_card_dai {
-	unsigned int fmt;
 	unsigned int sysclk;
+	unsigned int tx_slot_mask;
+	unsigned int rx_slot_mask;
+	int slots;
+	int slot_width;
 	struct clk *clk;
 	char dai_name[DAI_NAME_NUM];
 };
@@ -75,7 +78,7 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct rsrc_card_priv *priv =	snd_soc_card_get_drvdata(rtd->card);
 	struct rsrc_card_dai *dai_props =
-		rsrc_priv_to_props(priv, rtd - rtd->card->rtd);
+		rsrc_priv_to_props(priv, rtd->num);
 
 	return clk_prepare_enable(dai_props->clk);
 }
@@ -85,7 +88,7 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct rsrc_card_priv *priv =	snd_soc_card_get_drvdata(rtd->card);
 	struct rsrc_card_dai *dai_props =
-		rsrc_priv_to_props(priv, rtd - rtd->card->rtd);
+		rsrc_priv_to_props(priv, rtd->num);
 
 	clk_disable_unprepare(dai_props->clk);
 }
@@ -101,7 +104,7 @@
 	struct snd_soc_dai *dai;
 	struct snd_soc_dai_link *dai_link;
 	struct rsrc_card_dai *dai_props;
-	int num = rtd - rtd->card->rtd;
+	int num = rtd->num;
 	int ret;
 
 	dai_link	= rsrc_priv_to_link(priv, num);
@@ -110,14 +113,6 @@
 				rtd->cpu_dai :
 				rtd->codec_dai;
 
-	if (dai_props->fmt) {
-		ret = snd_soc_dai_set_fmt(dai, dai_props->fmt);
-		if (ret && ret != -ENOTSUPP) {
-			dev_err(dai->dev, "set_fmt error\n");
-			goto err;
-		}
-	}
-
 	if (dai_props->sysclk) {
 		ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0);
 		if (ret && ret != -ENOTSUPP) {
@@ -126,6 +121,18 @@
 		}
 	}
 
+	if (dai_props->slots) {
+		ret = snd_soc_dai_set_tdm_slot(dai,
+					       dai_props->tx_slot_mask,
+					       dai_props->rx_slot_mask,
+					       dai_props->slots,
+					       dai_props->slot_width);
+		if (ret && ret != -ENOTSUPP) {
+			dev_err(dai->dev, "set_tdm_slot error\n");
+			goto err;
+		}
+	}
+
 	ret = 0;
 
 err:
@@ -148,14 +155,13 @@
 }
 
 static int rsrc_card_parse_daifmt(struct device_node *node,
-				  struct device_node *np,
+				  struct device_node *codec,
 				  struct rsrc_card_priv *priv,
-				  int idx, bool is_fe)
+				  struct snd_soc_dai_link *dai_link,
+				  unsigned int *retfmt)
 {
-	struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
 	struct device_node *bitclkmaster = NULL;
 	struct device_node *framemaster = NULL;
-	struct device_node *codec = is_fe ? NULL : np;
 	unsigned int daifmt;
 
 	daifmt = snd_soc_of_parse_daifmt(node, NULL,
@@ -172,11 +178,11 @@
 		daifmt |= (codec == framemaster) ?
 			SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS;
 
-	dai_props->fmt	= daifmt;
-
 	of_node_put(bitclkmaster);
 	of_node_put(framemaster);
 
+	*retfmt = daifmt;
+
 	return 0;
 }
 
@@ -198,6 +204,15 @@
 	if (ret)
 		return ret;
 
+	/* Parse TDM slot */
+	ret = snd_soc_of_parse_tdm_slot(np,
+					&dai_props->tx_slot_mask,
+					&dai_props->rx_slot_mask,
+					&dai_props->slots,
+					&dai_props->slot_width);
+	if (ret)
+		return ret;
+
 	if (is_fe) {
 		/* BE is dummy */
 		dai_link->codec_of_node		= NULL;
@@ -208,7 +223,9 @@
 		dai_link->dynamic		= 1;
 		dai_link->dpcm_merged_format	= 1;
 		dai_link->cpu_of_node		= args.np;
-		snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name);
+		ret = snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name);
+		if (ret < 0)
+			return ret;
 
 		/* set dai_name */
 		snprintf(dai_props->dai_name, DAI_NAME_NUM, "fe.%s",
@@ -240,7 +257,9 @@
 		dai_link->no_pcm		= 1;
 		dai_link->be_hw_params_fixup	= rsrc_card_be_hw_params_fixup;
 		dai_link->codec_of_node		= args.np;
-		snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name);
+		ret = snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name);
+		if (ret < 0)
+			return ret;
 
 		/* additional name prefix */
 		if (of_data) {
@@ -305,23 +324,16 @@
 	return 0;
 }
 
-static int rsrc_card_dai_link_of(struct device_node *node,
-				 struct device_node *np,
-				 struct rsrc_card_priv *priv,
-				 int idx)
+static int rsrc_card_dai_sub_link_of(struct device_node *node,
+				     struct device_node *np,
+				     struct rsrc_card_priv *priv,
+				     int idx, bool is_fe)
 {
 	struct device *dev = rsrc_priv_to_dev(priv);
+	struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx);
 	struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
-	bool is_fe = false;
 	int ret;
 
-	if (0 == strcmp(np->name, "cpu"))
-		is_fe = true;
-
-	ret = rsrc_card_parse_daifmt(node, np, priv, idx, is_fe);
-	if (ret < 0)
-		return ret;
-
 	ret = rsrc_card_parse_links(np, priv, idx, is_fe);
 	if (ret < 0)
 		return ret;
@@ -332,12 +344,54 @@
 
 	dev_dbg(dev, "\t%s / %04x / %d\n",
 		dai_props->dai_name,
-		dai_props->fmt,
+		dai_link->dai_fmt,
 		dai_props->sysclk);
 
 	return ret;
 }
 
+static int rsrc_card_dai_link_of(struct device_node *node,
+				 struct rsrc_card_priv *priv)
+{
+	struct snd_soc_dai_link *dai_link;
+	struct device_node *np;
+	unsigned int daifmt = 0;
+	int ret, i;
+	bool is_fe;
+
+	/* find 1st codec */
+	i = 0;
+	for_each_child_of_node(node, np) {
+		dai_link = rsrc_priv_to_link(priv, i);
+
+		if (strcmp(np->name, "codec") == 0) {
+			ret = rsrc_card_parse_daifmt(node, np, priv,
+						     dai_link, &daifmt);
+			if (ret < 0)
+				return ret;
+			break;
+		}
+		i++;
+	}
+
+	i = 0;
+	for_each_child_of_node(node, np) {
+		dai_link = rsrc_priv_to_link(priv, i);
+		dai_link->dai_fmt = daifmt;
+
+		is_fe = false;
+		if (strcmp(np->name, "cpu") == 0)
+			is_fe = true;
+
+		ret = rsrc_card_dai_sub_link_of(node, np, priv, i, is_fe);
+		if (ret < 0)
+			return ret;
+		i++;
+	}
+
+	return 0;
+}
+
 static int rsrc_card_parse_of(struct device_node *node,
 			      struct rsrc_card_priv *priv,
 			      struct device *dev)
@@ -345,9 +399,8 @@
 	const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev);
 	struct rsrc_card_dai *props;
 	struct snd_soc_dai_link *links;
-	struct device_node *np;
 	int ret;
-	int i, num;
+	int num;
 
 	if (!node)
 		return -EINVAL;
@@ -388,13 +441,9 @@
 		priv->snd_card.name ? priv->snd_card.name : "",
 		priv->convert_rate);
 
-	i = 0;
-	for_each_child_of_node(node, np) {
-		ret = rsrc_card_dai_link_of(node, np, priv, i);
-		if (ret < 0)
-			return ret;
-		i++;
-	}
+	ret = rsrc_card_dai_link_of(node, priv);
+	if (ret < 0)
+		return ret;
 
 	if (!priv->snd_card.name)
 		priv->snd_card.name = priv->snd_card.dai_link->name;
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 68b439e..5eda056 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -20,20 +20,21 @@
 #define OUF_SRC(id)	((1 << (id + 16)) | (1 << id))
 
 struct rsnd_src {
-	struct rsnd_src_platform_info *info; /* rcar_snd.h */
 	struct rsnd_mod mod;
+	struct rsnd_mod *dma;
 	struct rsnd_kctrl_cfg_s sen;  /* sync convert enable */
 	struct rsnd_kctrl_cfg_s sync; /* sync convert */
 	u32 convert_rate; /* sampling rate convert */
 	int err;
+	int irq;
 };
 
 #define RSND_SRC_NAME_SIZE 16
 
+#define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id)
+#define rsnd_src_to_dma(src) ((src)->dma)
 #define rsnd_src_nr(priv) ((priv)->src_nr)
 #define rsnd_enable_sync_convert(src) ((src)->sen.val)
-#define rsnd_src_of_node(priv) \
-	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
 
 #define rsnd_mod_to_src(_mod)				\
 	container_of((_mod), struct rsnd_src, mod)
@@ -69,67 +70,16 @@
  *        |-----------------|
  */
 
-/*
- *	How to use SRC bypass mode for debugging
- *
- * SRC has bypass mode, and it is useful for debugging.
- * In Gen2 case,
- * SRCm_MODE controls whether SRC is used or not
- * SSI_MODE0 controls whether SSIU which receives SRC data
- * is used or not.
- * Both SRCm_MODE/SSI_MODE0 settings are needed if you use SRC,
- * but SRC bypass mode needs SSI_MODE0 only.
- *
- * This driver request
- * struct rsnd_src_platform_info {
- *	u32 convert_rate;
- *	int dma_id;
- * }
- *
- * rsnd_src_convert_rate() indicates
- * above convert_rate, and it controls
- * whether SRC is used or not.
- *
- * ex) doesn't use SRC
- * static struct rsnd_dai_platform_info rsnd_dai = {
- *	.playback = { .ssi = &rsnd_ssi[0], },
- * };
- *
- * ex) uses SRC
- * static struct rsnd_src_platform_info rsnd_src[] = {
- *	RSND_SCU(48000, 0),
- *	...
- * };
- * static struct rsnd_dai_platform_info rsnd_dai = {
- *	.playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] },
- * };
- *
- * ex) uses SRC bypass mode
- * static struct rsnd_src_platform_info rsnd_src[] = {
- *	RSND_SCU(0, 0),
- *	...
- * };
- * static struct rsnd_dai_platform_info rsnd_dai = {
- *	.playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] },
- * };
- *
- */
-
-/*
- *		Gen1/Gen2 common functions
- */
-static void rsnd_src_soft_reset(struct rsnd_mod *mod)
+static void rsnd_src_activation(struct rsnd_mod *mod)
 {
 	rsnd_mod_write(mod, SRC_SWRSR, 0);
 	rsnd_mod_write(mod, SRC_SWRSR, 1);
 }
 
-
-#define rsnd_src_initialize_lock(mod)	__rsnd_src_initialize_lock(mod, 1)
-#define rsnd_src_initialize_unlock(mod)	__rsnd_src_initialize_lock(mod, 0)
-static void __rsnd_src_initialize_lock(struct rsnd_mod *mod, u32 enable)
+static void rsnd_src_halt(struct rsnd_mod *mod)
 {
-	rsnd_mod_write(mod, SRC_SRCIR, enable);
+	rsnd_mod_write(mod, SRC_SRCIR, 1);
+	rsnd_mod_write(mod, SRC_SWRSR, 0);
 }
 
 static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io,
@@ -143,99 +93,6 @@
 					is_play ? "rx" : "tx");
 }
 
-int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
-			struct rsnd_dai_stream *io,
-			int use_busif)
-{
-	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-	int ssi_id = rsnd_mod_id(ssi_mod);
-
-	/*
-	 * SSI_MODE0
-	 */
-	rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id),
-		      !use_busif << ssi_id);
-
-	/*
-	 * SSI_MODE1
-	 */
-	if (rsnd_ssi_is_pin_sharing(io)) {
-		int shift = -1;
-		switch (ssi_id) {
-		case 1:
-			shift = 0;
-			break;
-		case 2:
-			shift = 2;
-			break;
-		case 4:
-			shift = 16;
-			break;
-		}
-
-		if (shift >= 0)
-			rsnd_mod_bset(ssi_mod, SSI_MODE1,
-				      0x3 << shift,
-				      rsnd_rdai_is_clk_master(rdai) ?
-				      0x2 << shift : 0x1 << shift);
-	}
-
-	/*
-	 * DMA settings for SSIU
-	 */
-	if (use_busif) {
-		u32 val = rsnd_get_dalign(ssi_mod, io);
-
-		rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR,
-			       rsnd_get_adinr_bit(ssi_mod, io));
-		rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE,  1);
-		rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1);
-
-		rsnd_mod_write(ssi_mod, SSI_BUSIF_DALIGN, val);
-	}
-
-	return 0;
-}
-
-int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
-		       struct rsnd_dai_stream *io)
-{
-	/*
-	 * DMA settings for SSIU
-	 */
-	rsnd_mod_write(ssi_mod, SSI_CTRL, 0);
-
-	return 0;
-}
-
-int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod)
-{
-	struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
-
-	if (rsnd_is_gen1(priv))
-		return 0;
-
-	/* enable SSI interrupt if Gen2 */
-	rsnd_mod_write(ssi_mod, SSI_INT_ENABLE,
-		       rsnd_ssi_is_dma_mode(ssi_mod) ?
-		       0x0e000000 : 0x0f000000);
-
-	return 0;
-}
-
-int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod)
-{
-	struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
-
-	if (rsnd_is_gen1(priv))
-		return 0;
-
-	/* disable SSI interrupt if Gen2 */
-	rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000);
-
-	return 0;
-}
-
 static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io,
 				 struct rsnd_src *src)
 {
@@ -283,34 +140,6 @@
 	return rate;
 }
 
-static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
-				     struct rsnd_dai_stream *io)
-{
-	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-	struct rsnd_src *src = rsnd_mod_to_src(mod);
-	u32 convert_rate = rsnd_src_convert_rate(io, src);
-	u32 fsrate = 0;
-
-	if (convert_rate)
-		fsrate = 0x0400000 / convert_rate * runtime->rate;
-
-	/* Set channel number and output bit length */
-	rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr_bit(mod, io));
-
-	/* Enable the initial value of IFS */
-	if (fsrate) {
-		rsnd_mod_write(mod, SRC_IFSCR, 1);
-
-		/* Set initial value of IFS */
-		rsnd_mod_write(mod, SRC_IFSVR, fsrate);
-	}
-
-	/* use DMA transfer */
-	rsnd_mod_write(mod, SRC_BUSIF_MODE, 1);
-
-	return 0;
-}
-
 static int rsnd_src_hw_params(struct rsnd_mod *mod,
 			      struct rsnd_dai_stream *io,
 			      struct snd_pcm_substream *substream,
@@ -319,9 +148,6 @@
 	struct rsnd_src *src = rsnd_mod_to_src(mod);
 	struct snd_soc_pcm_runtime *fe = substream->private_data;
 
-	/* default value (mainly for non-DT) */
-	src->convert_rate = src->info->convert_rate;
-
 	/*
 	 * SRC assumes that it is used under DPCM if user want to use
 	 * sampling rate convert. Then, SRC should be FE.
@@ -347,250 +173,112 @@
 	return 0;
 }
 
-static int rsnd_src_init(struct rsnd_mod *mod,
-			 struct rsnd_priv *priv)
-{
-	struct rsnd_src *src = rsnd_mod_to_src(mod);
-
-	rsnd_mod_power_on(mod);
-
-	rsnd_src_soft_reset(mod);
-
-	rsnd_src_initialize_lock(mod);
-
-	src->err = 0;
-
-	/* reset sync convert_rate */
-	src->sync.val = 0;
-
-	return 0;
-}
-
-static int rsnd_src_quit(struct rsnd_mod *mod,
-			 struct rsnd_dai_stream *io,
-			 struct rsnd_priv *priv)
-{
-	struct rsnd_src *src = rsnd_mod_to_src(mod);
-	struct device *dev = rsnd_priv_to_dev(priv);
-
-	rsnd_mod_power_off(mod);
-
-	if (src->err)
-		dev_warn(dev, "%s[%d] under/over flow err = %d\n",
-			 rsnd_mod_name(mod), rsnd_mod_id(mod), src->err);
-
-	src->convert_rate = 0;
-
-	/* reset sync convert_rate */
-	src->sync.val = 0;
-
-	return 0;
-}
-
-static int rsnd_src_start(struct rsnd_mod *mod)
-{
-	rsnd_src_initialize_unlock(mod);
-
-	return 0;
-}
-
-static int rsnd_src_stop(struct rsnd_mod *mod)
-{
-	/* nothing to do */
-	return 0;
-}
-
-/*
- *		Gen1 functions
- */
-static int rsnd_src_set_route_gen1(struct rsnd_dai_stream *io,
-				   struct rsnd_mod *mod)
-{
-	struct src_route_config {
-		u32 mask;
-		int shift;
-	} routes[] = {
-		{ 0xF,  0, }, /* 0 */
-		{ 0xF,  4, }, /* 1 */
-		{ 0xF,  8, }, /* 2 */
-		{ 0x7, 12, }, /* 3 */
-		{ 0x7, 16, }, /* 4 */
-		{ 0x7, 20, }, /* 5 */
-		{ 0x7, 24, }, /* 6 */
-		{ 0x3, 28, }, /* 7 */
-		{ 0x3, 30, }, /* 8 */
-	};
-	u32 mask;
-	u32 val;
-	int id;
-
-	id = rsnd_mod_id(mod);
-	if (id < 0 || id >= ARRAY_SIZE(routes))
-		return -EIO;
-
-	/*
-	 * SRC_ROUTE_SELECT
-	 */
-	val = rsnd_io_is_play(io) ? 0x1 : 0x2;
-	val = val		<< routes[id].shift;
-	mask = routes[id].mask	<< routes[id].shift;
-
-	rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val);
-
-	return 0;
-}
-
-static int rsnd_src_set_convert_timing_gen1(struct rsnd_dai_stream *io,
-					    struct rsnd_mod *mod)
+static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
+				      struct rsnd_mod *mod)
 {
 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-	struct rsnd_src *src = rsnd_mod_to_src(mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
 	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-	u32 convert_rate = rsnd_src_convert_rate(io, src);
-	u32 mask;
-	u32 val;
-	int shift;
-	int id = rsnd_mod_id(mod);
-	int ret;
-
-	/*
-	 * SRC_TIMING_SELECT
-	 */
-	shift	= (id % 4) * 8;
-	mask	= 0x1F << shift;
-
-	/*
-	 * ADG is used as source clock if SRC was used,
-	 * then, SSI WS is used as destination clock.
-	 * SSI WS is used as source clock if SRC is not used
-	 * (when playback, source/destination become reverse when capture)
-	 */
-	ret = 0;
-	if (convert_rate) {
-		/* use ADG */
-		val = 0;
-		ret = rsnd_adg_set_convert_clk_gen1(priv, mod,
-						    runtime->rate,
-						    convert_rate);
-	} else if (8 == id) {
-		/* use SSI WS, but SRU8 is special */
-		val = id << shift;
-	} else {
-		/* use SSI WS */
-		val = (id + 1) << shift;
-	}
-
-	if (ret < 0)
-		return ret;
-
-	switch (id / 4) {
-	case 0:
-		rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val);
-		break;
-	case 1:
-		rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val);
-		break;
-	case 2:
-		rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val);
-		break;
-	}
-
-	return 0;
-}
-
-static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
-					  struct rsnd_dai_stream *io)
-{
 	struct rsnd_src *src = rsnd_mod_to_src(mod);
-	int ret;
+	u32 convert_rate = rsnd_src_convert_rate(io, src);
+	u32 ifscr, fsrate, adinr;
+	u32 cr, route;
+	u32 bsdsr, bsisr;
+	uint ratio;
 
-	ret = rsnd_src_set_convert_rate(mod, io);
-	if (ret < 0)
-		return ret;
+	if (!runtime)
+		return;
 
-	/* Select SRC mode (fixed value) */
-	rsnd_mod_write(mod, SRC_SRCCR, 0x00010110);
+	/* 6 - 1/6 are very enough ratio for SRC_BSDSR */
+	if (!convert_rate)
+		ratio = 0;
+	else if (convert_rate > runtime->rate)
+		ratio = 100 * convert_rate / runtime->rate;
+	else
+		ratio = 100 * runtime->rate / convert_rate;
 
-	/* Set the restriction value of the FS ratio (98%) */
-	rsnd_mod_write(mod, SRC_MNFSR,
-		       rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98);
+	if (ratio > 600) {
+		dev_err(dev, "FSO/FSI ratio error\n");
+		return;
+	}
 
-	/* Gen1/Gen2 are not compatible */
-	if (rsnd_src_convert_rate(io, src))
-		rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
+	/*
+	 *	SRC_ADINR
+	 */
+	adinr = rsnd_get_adinr_bit(mod, io) |
+		rsnd_get_adinr_chan(mod, io);
 
-	/* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */
+	/*
+	 *	SRC_IFSCR / SRC_IFSVR
+	 */
+	ifscr = 0;
+	fsrate = 0;
+	if (convert_rate) {
+		ifscr = 1;
+		fsrate = 0x0400000 / convert_rate * runtime->rate;
+	}
 
-	return 0;
+	/*
+	 *	SRC_SRCCR / SRC_ROUTE_MODE0
+	 */
+	cr	= 0x00011110;
+	route	= 0x0;
+	if (convert_rate) {
+		route	= 0x1;
+
+		if (rsnd_enable_sync_convert(src)) {
+			cr |= 0x1;
+			route |= rsnd_io_is_play(io) ?
+				(0x1 << 24) : (0x1 << 25);
+		}
+	}
+
+	/*
+	 * SRC_BSDSR / SRC_BSISR
+	 */
+	switch (rsnd_mod_id(mod)) {
+	case 5:
+	case 6:
+	case 7:
+	case 8:
+		bsdsr = 0x02400000; /* 6 - 1/6 */
+		bsisr = 0x00100060; /* 6 - 1/6 */
+		break;
+	default:
+		bsdsr = 0x01800000; /* 6 - 1/6 */
+		bsisr = 0x00100060 ;/* 6 - 1/6 */
+		break;
+	}
+
+	rsnd_mod_write(mod, SRC_SRCIR, 1);	/* initialize */
+	rsnd_mod_write(mod, SRC_ADINR, adinr);
+	rsnd_mod_write(mod, SRC_IFSCR, ifscr);
+	rsnd_mod_write(mod, SRC_IFSVR, fsrate);
+	rsnd_mod_write(mod, SRC_SRCCR, cr);
+	rsnd_mod_write(mod, SRC_BSDSR, bsdsr);
+	rsnd_mod_write(mod, SRC_BSISR, bsisr);
+	rsnd_mod_write(mod, SRC_SRCIR, 0);	/* cancel initialize */
+
+	rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
+	rsnd_mod_write(mod, SRC_I_BUSIF_MODE, 1);
+	rsnd_mod_write(mod, SRC_O_BUSIF_MODE, 1);
+	rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
+
+	if (convert_rate)
+		rsnd_adg_set_convert_clk_gen2(mod, io,
+					      runtime->rate,
+					      convert_rate);
+	else
+		rsnd_adg_set_convert_timing_gen2(mod, io);
 }
 
-static int rsnd_src_init_gen1(struct rsnd_mod *mod,
-			      struct rsnd_dai_stream *io,
-			      struct rsnd_priv *priv)
-{
-	int ret;
-
-	ret = rsnd_src_init(mod, priv);
-	if (ret < 0)
-		return ret;
-
-	ret = rsnd_src_set_route_gen1(io, mod);
-	if (ret < 0)
-		return ret;
-
-	ret = rsnd_src_set_convert_rate_gen1(mod, io);
-	if (ret < 0)
-		return ret;
-
-	ret = rsnd_src_set_convert_timing_gen1(io, mod);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static int rsnd_src_start_gen1(struct rsnd_mod *mod,
-			       struct rsnd_dai_stream *io,
-			       struct rsnd_priv *priv)
-{
-	int id = rsnd_mod_id(mod);
-
-	rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id));
-
-	return rsnd_src_start(mod);
-}
-
-static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
-			      struct rsnd_dai_stream *io,
-			      struct rsnd_priv *priv)
-{
-	int id = rsnd_mod_id(mod);
-
-	rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0);
-
-	return rsnd_src_stop(mod);
-}
-
-static struct rsnd_mod_ops rsnd_src_gen1_ops = {
-	.name	= SRC_NAME,
-	.dma_req = rsnd_src_dma_req,
-	.init	= rsnd_src_init_gen1,
-	.quit	= rsnd_src_quit,
-	.start	= rsnd_src_start_gen1,
-	.stop	= rsnd_src_stop_gen1,
-	.hw_params = rsnd_src_hw_params,
-};
-
-/*
- *		Gen2 functions
- */
-#define rsnd_src_irq_enable_gen2(mod)  rsnd_src_irq_ctrol_gen2(mod, 1)
-#define rsnd_src_irq_disable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 0)
-static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable)
+#define rsnd_src_irq_enable(mod)  rsnd_src_irq_ctrol(mod, 1)
+#define rsnd_src_irq_disable(mod) rsnd_src_irq_ctrol(mod, 0)
+static void rsnd_src_irq_ctrol(struct rsnd_mod *mod, int enable)
 {
 	struct rsnd_src *src = rsnd_mod_to_src(mod);
 	u32 sys_int_val, int_val, sys_int_mask;
-	int irq = src->info->irq;
+	int irq = src->irq;
 	int id = rsnd_mod_id(mod);
 
 	sys_int_val =
@@ -600,7 +288,7 @@
 	/*
 	 * IRQ is not supported on non-DT
 	 * see
-	 *	rsnd_src_probe_gen2()
+	 *	rsnd_src_probe_()
 	 */
 	if ((irq <= 0) || !enable) {
 		sys_int_val = 0;
@@ -620,7 +308,7 @@
 	rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val);
 }
 
-static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod)
+static void rsnd_src_status_clear(struct rsnd_mod *mod)
 {
 	u32 val = OUF_SRC(rsnd_mod_id(mod));
 
@@ -628,7 +316,7 @@
 	rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val);
 }
 
-static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod)
+static bool rsnd_src_record_error(struct rsnd_mod *mod)
 {
 	struct rsnd_src *src = rsnd_mod_to_src(mod);
 	u32 val0, val1;
@@ -652,22 +340,16 @@
 		ret = true;
 	}
 
-	/* clear error static */
-	rsnd_src_error_clear_gen2(mod);
-
 	return ret;
 }
 
-static int _rsnd_src_start_gen2(struct rsnd_mod *mod,
-				struct rsnd_dai_stream *io)
+static int rsnd_src_start(struct rsnd_mod *mod,
+			  struct rsnd_dai_stream *io,
+			  struct rsnd_priv *priv)
 {
 	struct rsnd_src *src = rsnd_mod_to_src(mod);
 	u32 val;
 
-	val = rsnd_get_dalign(mod, io);
-
-	rsnd_mod_write(mod, SRC_BUSIF_DALIGN, val);
-
 	/*
 	 * WORKAROUND
 	 *
@@ -678,247 +360,149 @@
 
 	rsnd_mod_write(mod, SRC_CTRL, val);
 
-	rsnd_src_error_clear_gen2(mod);
+	return 0;
+}
 
-	rsnd_src_start(mod);
-
-	rsnd_src_irq_enable_gen2(mod);
+static int rsnd_src_stop(struct rsnd_mod *mod,
+			 struct rsnd_dai_stream *io,
+			 struct rsnd_priv *priv)
+{
+	/*
+	 * stop SRC output only
+	 * see rsnd_src_quit
+	 */
+	rsnd_mod_write(mod, SRC_CTRL, 0x01);
 
 	return 0;
 }
 
-static int _rsnd_src_stop_gen2(struct rsnd_mod *mod)
+static int rsnd_src_init(struct rsnd_mod *mod,
+			 struct rsnd_dai_stream *io,
+			 struct rsnd_priv *priv)
 {
-	rsnd_src_irq_disable_gen2(mod);
+	struct rsnd_src *src = rsnd_mod_to_src(mod);
 
-	rsnd_mod_write(mod, SRC_CTRL, 0);
+	rsnd_mod_power_on(mod);
 
-	rsnd_src_error_record_gen2(mod);
+	rsnd_src_activation(mod);
 
-	return rsnd_src_stop(mod);
+	rsnd_src_set_convert_rate(io, mod);
+
+	rsnd_src_status_clear(mod);
+
+	rsnd_src_irq_enable(mod);
+
+	src->err = 0;
+
+	/* reset sync convert_rate */
+	src->sync.val = 0;
+
+	return 0;
 }
 
-static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod,
-				      struct rsnd_dai_stream *io)
+static int rsnd_src_quit(struct rsnd_mod *mod,
+			 struct rsnd_dai_stream *io,
+			 struct rsnd_priv *priv)
+{
+	struct rsnd_src *src = rsnd_mod_to_src(mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
+
+	rsnd_src_irq_disable(mod);
+
+	/* stop both out/in */
+	rsnd_mod_write(mod, SRC_CTRL, 0);
+
+	rsnd_src_halt(mod);
+
+	rsnd_mod_power_off(mod);
+
+	if (src->err)
+		dev_warn(dev, "%s[%d] under/over flow err = %d\n",
+			 rsnd_mod_name(mod), rsnd_mod_id(mod), src->err);
+
+	src->convert_rate = 0;
+
+	/* reset sync convert_rate */
+	src->sync.val = 0;
+
+	return 0;
+}
+
+static void __rsnd_src_interrupt(struct rsnd_mod *mod,
+				 struct rsnd_dai_stream *io)
 {
 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct rsnd_src *src = rsnd_mod_to_src(mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
 
 	spin_lock(&priv->lock);
 
 	/* ignore all cases if not working */
 	if (!rsnd_io_is_working(io))
-		goto rsnd_src_interrupt_gen2_out;
+		goto rsnd_src_interrupt_out;
 
-	if (rsnd_src_error_record_gen2(mod)) {
-		struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-		struct rsnd_src *src = rsnd_mod_to_src(mod);
-		struct device *dev = rsnd_priv_to_dev(priv);
+	if (rsnd_src_record_error(mod)) {
 
 		dev_dbg(dev, "%s[%d] restart\n",
 			rsnd_mod_name(mod), rsnd_mod_id(mod));
 
-		_rsnd_src_stop_gen2(mod);
-		if (src->err < 1024)
-			_rsnd_src_start_gen2(mod, io);
-		else
-			dev_warn(dev, "no more SRC restart\n");
+		rsnd_src_stop(mod, io, priv);
+		rsnd_src_start(mod, io, priv);
 	}
 
-rsnd_src_interrupt_gen2_out:
+	if (src->err > 1024) {
+		rsnd_src_irq_disable(mod);
+
+		dev_warn(dev, "no more %s[%d] restart\n",
+			 rsnd_mod_name(mod), rsnd_mod_id(mod));
+	}
+
+	rsnd_src_status_clear(mod);
+rsnd_src_interrupt_out:
+
 	spin_unlock(&priv->lock);
 }
 
-static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
+static irqreturn_t rsnd_src_interrupt(int irq, void *data)
 {
 	struct rsnd_mod *mod = data;
 
-	rsnd_mod_interrupt(mod, __rsnd_src_interrupt_gen2);
+	rsnd_mod_interrupt(mod, __rsnd_src_interrupt);
 
 	return IRQ_HANDLED;
 }
 
-static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
-					  struct rsnd_dai_stream *io)
-{
-	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-	struct device *dev = rsnd_priv_to_dev(priv);
-	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-	struct rsnd_src *src = rsnd_mod_to_src(mod);
-	u32 convert_rate = rsnd_src_convert_rate(io, src);
-	u32 cr, route;
-	uint ratio;
-	int ret;
-
-	/* 6 - 1/6 are very enough ratio for SRC_BSDSR */
-	if (!convert_rate)
-		ratio = 0;
-	else if (convert_rate > runtime->rate)
-		ratio = 100 * convert_rate / runtime->rate;
-	else
-		ratio = 100 * runtime->rate / convert_rate;
-
-	if (ratio > 600) {
-		dev_err(dev, "FSO/FSI ratio error\n");
-		return -EINVAL;
-	}
-
-	ret = rsnd_src_set_convert_rate(mod, io);
-	if (ret < 0)
-		return ret;
-
-	cr	= 0x00011110;
-	route	= 0x0;
-	if (convert_rate) {
-		route	= 0x1;
-
-		if (rsnd_enable_sync_convert(src)) {
-			cr |= 0x1;
-			route |= rsnd_io_is_play(io) ?
-				(0x1 << 24) : (0x1 << 25);
-		}
-	}
-
-	rsnd_mod_write(mod, SRC_SRCCR, cr);
-	rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
-
-	switch (rsnd_mod_id(mod)) {
-	case 5:
-	case 6:
-	case 7:
-	case 8:
-		rsnd_mod_write(mod, SRC_BSDSR, 0x02400000);
-		break;
-	default:
-		rsnd_mod_write(mod, SRC_BSDSR, 0x01800000);
-		break;
-	}
-
-	rsnd_mod_write(mod, SRC_BSISR, 0x00100060);
-
-	return 0;
-}
-
-static int rsnd_src_set_convert_timing_gen2(struct rsnd_dai_stream *io,
-					    struct rsnd_mod *mod)
-{
-	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-	struct rsnd_src *src = rsnd_mod_to_src(mod);
-	u32 convert_rate = rsnd_src_convert_rate(io, src);
-	int ret;
-
-	if (convert_rate)
-		ret = rsnd_adg_set_convert_clk_gen2(mod, io,
-						    runtime->rate,
-						    convert_rate);
-	else
-		ret = rsnd_adg_set_convert_timing_gen2(mod, io);
-
-	return ret;
-}
-
-static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
-			       struct rsnd_dai_stream *io,
-			       struct rsnd_priv *priv)
+static int rsnd_src_probe_(struct rsnd_mod *mod,
+			   struct rsnd_dai_stream *io,
+			   struct rsnd_priv *priv)
 {
 	struct rsnd_src *src = rsnd_mod_to_src(mod);
 	struct device *dev = rsnd_priv_to_dev(priv);
-	int irq = src->info->irq;
+	int irq = src->irq;
 	int ret;
 
 	if (irq > 0) {
 		/*
 		 * IRQ is not supported on non-DT
 		 * see
-		 *	rsnd_src_irq_enable_gen2()
+		 *	rsnd_src_irq_enable()
 		 */
 		ret = devm_request_irq(dev, irq,
-				       rsnd_src_interrupt_gen2,
+				       rsnd_src_interrupt,
 				       IRQF_SHARED,
 				       dev_name(dev), mod);
 		if (ret)
 			return ret;
 	}
 
-	ret = rsnd_dma_init(io,
-			    rsnd_mod_to_dma(mod),
-			    src->info->dma_id);
+	src->dma = rsnd_dma_attach(io, mod, 0);
+	if (IS_ERR(src->dma))
+		return PTR_ERR(src->dma);
 
 	return ret;
 }
 
-static int rsnd_src_remove_gen2(struct rsnd_mod *mod,
-				struct rsnd_dai_stream *io,
-				struct rsnd_priv *priv)
-{
-	rsnd_dma_quit(io, rsnd_mod_to_dma(mod));
-
-	return 0;
-}
-
-static int rsnd_src_init_gen2(struct rsnd_mod *mod,
-			      struct rsnd_dai_stream *io,
-			      struct rsnd_priv *priv)
-{
-	int ret;
-
-	ret = rsnd_src_init(mod, priv);
-	if (ret < 0)
-		return ret;
-
-	ret = rsnd_src_set_convert_rate_gen2(mod, io);
-	if (ret < 0)
-		return ret;
-
-	ret = rsnd_src_set_convert_timing_gen2(io, mod);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static int rsnd_src_start_gen2(struct rsnd_mod *mod,
-			       struct rsnd_dai_stream *io,
-			       struct rsnd_priv *priv)
-{
-	rsnd_dma_start(io, rsnd_mod_to_dma(mod));
-
-	return _rsnd_src_start_gen2(mod, io);
-}
-
-static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
-			      struct rsnd_dai_stream *io,
-			      struct rsnd_priv *priv)
-{
-	int ret;
-
-	ret = _rsnd_src_stop_gen2(mod);
-
-	rsnd_dma_stop(io, rsnd_mod_to_dma(mod));
-
-	return ret;
-}
-
-static void rsnd_src_reconvert_update(struct rsnd_dai_stream *io,
-				      struct rsnd_mod *mod)
-{
-	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-	struct rsnd_src *src = rsnd_mod_to_src(mod);
-	u32 convert_rate = rsnd_src_convert_rate(io, src);
-	u32 fsrate;
-
-	if (!runtime)
-		return;
-
-	if (!convert_rate)
-		convert_rate = runtime->rate;
-
-	fsrate = 0x0400000 / convert_rate * runtime->rate;
-
-	/* update IFS */
-	rsnd_mod_write(mod, SRC_IFSVR, fsrate);
-}
-
-static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod,
+static int rsnd_src_pcm_new(struct rsnd_mod *mod,
 			    struct rsnd_dai_stream *io,
 			    struct snd_soc_pcm_runtime *rtd)
 {
@@ -950,7 +534,7 @@
 			       rsnd_io_is_play(io) ?
 			       "SRC Out Rate Switch" :
 			       "SRC In Rate Switch",
-			       rsnd_src_reconvert_update,
+			       rsnd_src_set_convert_rate,
 			       &src->sen, 1);
 	if (ret < 0)
 		return ret;
@@ -959,23 +543,22 @@
 			       rsnd_io_is_play(io) ?
 			       "SRC Out Rate" :
 			       "SRC In Rate",
-			       rsnd_src_reconvert_update,
+			       rsnd_src_set_convert_rate,
 			       &src->sync, 192000);
 
 	return ret;
 }
 
-static struct rsnd_mod_ops rsnd_src_gen2_ops = {
+static struct rsnd_mod_ops rsnd_src_ops = {
 	.name	= SRC_NAME,
 	.dma_req = rsnd_src_dma_req,
-	.probe	= rsnd_src_probe_gen2,
-	.remove	= rsnd_src_remove_gen2,
-	.init	= rsnd_src_init_gen2,
+	.probe	= rsnd_src_probe_,
+	.init	= rsnd_src_init,
 	.quit	= rsnd_src_quit,
-	.start	= rsnd_src_start_gen2,
-	.stop	= rsnd_src_stop_gen2,
+	.start	= rsnd_src_start,
+	.stop	= rsnd_src_stop,
 	.hw_params = rsnd_src_hw_params,
-	.pcm_new = rsnd_src_pcm_new_gen2,
+	.pcm_new = rsnd_src_pcm_new,
 };
 
 struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
@@ -983,113 +566,78 @@
 	if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv)))
 		id = 0;
 
-	return rsnd_mod_get((struct rsnd_src *)(priv->src) + id);
+	return rsnd_mod_get(rsnd_src_get(priv, id));
 }
 
-static void rsnd_of_parse_src(struct platform_device *pdev,
-			      const struct rsnd_of_data *of_data,
-			      struct rsnd_priv *priv)
+int rsnd_src_probe(struct rsnd_priv *priv)
 {
-	struct device_node *src_node;
+	struct device_node *node;
 	struct device_node *np;
-	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-	struct rsnd_src_platform_info *src_info;
-	struct device *dev = &pdev->dev;
-	int nr, i;
-
-	if (!of_data)
-		return;
-
-	src_node = rsnd_src_of_node(priv);
-	if (!src_node)
-		return;
-
-	nr = of_get_child_count(src_node);
-	if (!nr)
-		goto rsnd_of_parse_src_end;
-
-	src_info = devm_kzalloc(dev,
-				sizeof(struct rsnd_src_platform_info) * nr,
-				GFP_KERNEL);
-	if (!src_info) {
-		dev_err(dev, "src info allocation error\n");
-		goto rsnd_of_parse_src_end;
-	}
-
-	info->src_info		= src_info;
-	info->src_info_nr	= nr;
-
-	i = 0;
-	for_each_child_of_node(src_node, np) {
-		src_info[i].irq = irq_of_parse_and_map(np, 0);
-
-		i++;
-	}
-
-rsnd_of_parse_src_end:
-	of_node_put(src_node);
-}
-
-int rsnd_src_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv)
-{
-	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_src *src;
-	struct rsnd_mod_ops *ops;
 	struct clk *clk;
 	char name[RSND_SRC_NAME_SIZE];
 	int i, nr, ret;
 
-	ops = NULL;
-	if (rsnd_is_gen1(priv)) {
-		ops = &rsnd_src_gen1_ops;
-		dev_warn(dev, "Gen1 support will be removed soon\n");
-	}
-	if (rsnd_is_gen2(priv))
-		ops = &rsnd_src_gen2_ops;
-	if (!ops) {
-		dev_err(dev, "unknown Generation\n");
-		return -EIO;
-	}
-
-	rsnd_of_parse_src(pdev, of_data, priv);
-
-	/*
-	 * init SRC
-	 */
-	nr	= info->src_info_nr;
-	if (!nr)
+	/* This driver doesn't support Gen1 at this point */
+	if (rsnd_is_gen1(priv))
 		return 0;
 
+	node = rsnd_src_of_node(priv);
+	if (!node)
+		return 0; /* not used is not error */
+
+	nr = of_get_child_count(node);
+	if (!nr) {
+		ret = -EINVAL;
+		goto rsnd_src_probe_done;
+	}
+
 	src	= devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL);
-	if (!src)
-		return -ENOMEM;
+	if (!src) {
+		ret = -ENOMEM;
+		goto rsnd_src_probe_done;
+	}
 
 	priv->src_nr	= nr;
 	priv->src	= src;
 
-	for_each_rsnd_src(src, priv, i) {
+	i = 0;
+	for_each_child_of_node(node, np) {
+		src = rsnd_src_get(priv, i);
+
 		snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d",
 			 SRC_NAME, i);
 
+		src->irq = irq_of_parse_and_map(np, 0);
+		if (!src->irq) {
+			ret = -EINVAL;
+			goto rsnd_src_probe_done;
+		}
+
 		clk = devm_clk_get(dev, name);
-		if (IS_ERR(clk))
-			return PTR_ERR(clk);
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			goto rsnd_src_probe_done;
+		}
 
-		src->info = &info->src_info[i];
-
-		ret = rsnd_mod_init(priv, rsnd_mod_get(src), ops, clk, RSND_MOD_SRC, i);
+		ret = rsnd_mod_init(priv, rsnd_mod_get(src),
+				    &rsnd_src_ops, clk, RSND_MOD_SRC, i);
 		if (ret)
-			return ret;
+			goto rsnd_src_probe_done;
+
+		i++;
 	}
 
-	return 0;
+	ret = 0;
+
+rsnd_src_probe_done:
+	of_node_put(node);
+
+	return ret;
 }
 
-void rsnd_src_remove(struct platform_device *pdev,
-		     struct rsnd_priv *priv)
+void rsnd_src_remove(struct rsnd_priv *priv)
 {
 	struct rsnd_src *src;
 	int i;
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 1427ec2..7ee89da 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -24,7 +24,9 @@
 #define	OIEN		(1 << 26)	/* Overflow Interrupt Enable */
 #define	IIEN		(1 << 25)	/* Idle Mode Interrupt Enable */
 #define	DIEN		(1 << 24)	/* Data Interrupt Enable */
-
+#define	CHNL_4		(1 << 22)	/* Channels */
+#define	CHNL_6		(2 << 22)	/* Channels */
+#define	CHNL_8		(3 << 22)	/* Channels */
 #define	DWL_8		(0 << 19)	/* Data Word Length */
 #define	DWL_16		(1 << 19)	/* Data Word Length */
 #define	DWL_18		(2 << 19)	/* Data Word Length */
@@ -39,6 +41,7 @@
 #define	SCKP		(1 << 13)	/* Serial Bit Clock Polarity */
 #define	SWSP		(1 << 12)	/* Serial WS Polarity */
 #define	SDTA		(1 << 10)	/* Serial Data Alignment */
+#define	PDTA		(1 <<  9)	/* Parallel Data Alignment */
 #define	DEL		(1 <<  8)	/* Serial Data Delay */
 #define	CKDV(v)		(v <<  4)	/* Serial Clock Division Ratio */
 #define	TRMD		(1 <<  1)	/* Transmit/Receive Mode Select */
@@ -56,35 +59,44 @@
  * SSIWSR
  */
 #define CONT		(1 << 8)	/* WS Continue Function */
+#define WS_MODE		(1 << 0)	/* WS Mode */
 
 #define SSI_NAME "ssi"
 
 struct rsnd_ssi {
-	struct rsnd_ssi_platform_info *info; /* rcar_snd.h */
 	struct rsnd_ssi *parent;
 	struct rsnd_mod mod;
+	struct rsnd_mod *dma;
 
+	u32 flags;
 	u32 cr_own;
 	u32 cr_clk;
+	u32 cr_mode;
+	u32 wsr;
 	int chan;
+	int rate;
 	int err;
+	int irq;
 	unsigned int usrcnt;
 };
 
+/* flags */
+#define RSND_SSI_CLK_PIN_SHARE		(1 << 0)
+#define RSND_SSI_NO_BUSIF		(1 << 1) /* SSI+DMA without BUSIF */
+
 #define for_each_rsnd_ssi(pos, priv, i)					\
 	for (i = 0;							\
 	     (i < rsnd_ssi_nr(priv)) &&					\
 		((pos) = ((struct rsnd_ssi *)(priv)->ssi + i));		\
 	     i++)
 
+#define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id)
+#define rsnd_ssi_to_dma(mod) ((ssi)->dma)
 #define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
 #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
-#define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0)
-#define rsnd_ssi_parent(ssi) ((ssi)->parent)
-#define rsnd_ssi_mode_flags(p) ((p)->info->flags)
-#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
-#define rsnd_ssi_of_node(priv) \
-	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
+#define rsnd_ssi_mode_flags(p) ((p)->flags)
+#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io))
+#define rsnd_ssi_is_multi_slave(ssi, io) ((mod) != rsnd_io_to_mod_ssi(io))
 
 int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
 {
@@ -103,6 +115,16 @@
 	return use_busif;
 }
 
+static void rsnd_ssi_status_clear(struct rsnd_mod *mod)
+{
+	rsnd_mod_write(mod, SSISR, 0);
+}
+
+static u32 rsnd_ssi_status_get(struct rsnd_mod *mod)
+{
+	return rsnd_mod_read(mod, SSISR);
+}
+
 static void rsnd_ssi_status_check(struct rsnd_mod *mod,
 				  u32 bit)
 {
@@ -112,7 +134,7 @@
 	int i;
 
 	for (i = 0; i < 1024; i++) {
-		status = rsnd_mod_read(mod, SSISR);
+		status = rsnd_ssi_status_get(mod);
 		if (status & bit)
 			return;
 
@@ -122,13 +144,79 @@
 	dev_warn(dev, "status check failed\n");
 }
 
+static int rsnd_ssi_irq_enable(struct rsnd_mod *ssi_mod)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+
+	if (rsnd_is_gen1(priv))
+		return 0;
+
+	/* enable SSI interrupt if Gen2 */
+	rsnd_mod_write(ssi_mod, SSI_INT_ENABLE,
+		       rsnd_ssi_is_dma_mode(ssi_mod) ?
+		       0x0e000000 : 0x0f000000);
+
+	return 0;
+}
+
+static int rsnd_ssi_irq_disable(struct rsnd_mod *ssi_mod)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+
+	if (rsnd_is_gen1(priv))
+		return 0;
+
+	/* disable SSI interrupt if Gen2 */
+	rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000);
+
+	return 0;
+}
+
+u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io)
+{
+	struct rsnd_mod *mod;
+	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+	struct rsnd_priv *priv = rsnd_io_to_priv(io);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	enum rsnd_mod_type types[] = {
+		RSND_MOD_SSIM1,
+		RSND_MOD_SSIM2,
+		RSND_MOD_SSIM3,
+	};
+	int i, mask;
+
+	switch (runtime->channels) {
+	case 2: /* Multi channel is not needed for Stereo */
+		return 0;
+	case 6:
+		break;
+	default:
+		dev_err(dev, "unsupported channel\n");
+		return 0;
+	}
+
+	mask = 0;
+	for (i = 0; i < ARRAY_SIZE(types); i++) {
+		mod = rsnd_io_to_mod(io, types[i]);
+		if (!mod)
+			continue;
+
+		mask |= 1 << rsnd_mod_id(mod);
+	}
+
+	return mask;
+}
+
 static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
 				     struct rsnd_dai_stream *io)
 {
 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
 	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
 	struct device *dev = rsnd_priv_to_dev(priv);
+	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
 	struct rsnd_mod *mod = rsnd_mod_get(ssi);
+	struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
+	int slots = rsnd_get_slot_width(io);
 	int j, ret;
 	int ssi_clk_mul_table[] = {
 		1, 2, 4, 8, 16, 6, 12,
@@ -136,6 +224,24 @@
 	unsigned int main_rate;
 	unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime);
 
+	if (!rsnd_rdai_is_clk_master(rdai))
+		return 0;
+
+	if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io))
+		return 0;
+
+	if (rsnd_ssi_is_multi_slave(mod, io))
+		return 0;
+
+	if (ssi->usrcnt > 1) {
+		if (ssi->rate != rate) {
+			dev_err(dev, "SSI parent/child should use same rate\n");
+			return -EINVAL;
+		}
+
+		return 0;
+	}
+
 	/*
 	 * Find best clock, and try to start ADG
 	 */
@@ -143,15 +249,18 @@
 
 		/*
 		 * this driver is assuming that
-		 * system word is 64fs (= 2 x 32bit)
+		 * system word is 32bit x slots
 		 * see rsnd_ssi_init()
 		 */
-		main_rate = rate * 32 * 2 * ssi_clk_mul_table[j];
+		main_rate = rate * 32 * slots * ssi_clk_mul_table[j];
 
 		ret = rsnd_adg_ssi_clk_try_start(mod, main_rate);
 		if (0 == ret) {
 			ssi->cr_clk	= FORCE | SWL_32 |
 				SCKD | SWSD | CKDV(j);
+			ssi->wsr = CONT;
+
+			ssi->rate = rate;
 
 			dev_dbg(dev, "%s[%d] outputs %u Hz\n",
 				rsnd_mod_name(mod),
@@ -165,113 +274,91 @@
 	return -EIO;
 }
 
-static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi)
+static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi,
+				     struct rsnd_dai_stream *io)
 {
+	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
 	struct rsnd_mod *mod = rsnd_mod_get(ssi);
+	struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
 
-	ssi->cr_clk = 0;
+	if (!rsnd_rdai_is_clk_master(rdai))
+		return;
+
+	if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io))
+		return;
+
+	if (ssi->usrcnt > 1)
+		return;
+
+	ssi->cr_clk	= 0;
+	ssi->rate	= 0;
+
 	rsnd_adg_ssi_clk_stop(mod);
 }
 
-static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
-			      struct rsnd_dai_stream *io)
+static int rsnd_ssi_config_init(struct rsnd_ssi *ssi,
+				struct rsnd_dai_stream *io)
 {
-	struct rsnd_priv *priv = rsnd_io_to_priv(io);
 	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-	struct device *dev = rsnd_priv_to_dev(priv);
-	struct rsnd_mod *mod = rsnd_mod_get(ssi);
+	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+	u32 cr_own;
 	u32 cr_mode;
-	u32 cr;
+	u32 wsr;
+	int is_tdm;
 
-	if (0 == ssi->usrcnt) {
-		rsnd_mod_power_on(mod);
+	is_tdm = (rsnd_get_slot_width(io) >= 6) ? 1 : 0;
 
-		if (rsnd_rdai_is_clk_master(rdai)) {
-			struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
+	/*
+	 * always use 32bit system word.
+	 * see also rsnd_ssi_master_clk_enable()
+	 */
+	cr_own = FORCE | SWL_32 | PDTA;
 
-			if (ssi_parent)
-				rsnd_ssi_hw_start(ssi_parent, io);
-			else
-				rsnd_ssi_master_clk_start(ssi, io);
-		}
+	if (rdai->bit_clk_inv)
+		cr_own |= SCKP;
+	if (rdai->frm_clk_inv ^ is_tdm)
+		cr_own |= SWSP;
+	if (rdai->data_alignment)
+		cr_own |= SDTA;
+	if (rdai->sys_delay)
+		cr_own |= DEL;
+	if (rsnd_io_is_play(io))
+		cr_own |= TRMD;
+
+	switch (runtime->sample_bits) {
+	case 16:
+		cr_own |= DWL_16;
+		break;
+	case 32:
+		cr_own |= DWL_24;
+		break;
+	default:
+		return -EINVAL;
 	}
 
-	if (rsnd_ssi_is_dma_mode(mod)) {
+	if (rsnd_ssi_is_dma_mode(rsnd_mod_get(ssi))) {
 		cr_mode = UIEN | OIEN |	/* over/under run */
 			  DMEN;		/* DMA : enable DMA */
 	} else {
 		cr_mode = DIEN;		/* PIO : enable Data interrupt */
 	}
 
-	cr  =	ssi->cr_own	|
-		ssi->cr_clk	|
-		cr_mode		|
-		EN;
-
-	rsnd_mod_write(mod, SSICR, cr);
-
-	/* enable WS continue */
-	if (rsnd_rdai_is_clk_master(rdai))
-		rsnd_mod_write(mod, SSIWSR, CONT);
-
-	/* clear error status */
-	rsnd_mod_write(mod, SSISR, 0);
-
-	ssi->usrcnt++;
-
-	dev_dbg(dev, "%s[%d] hw started\n",
-		rsnd_mod_name(mod), rsnd_mod_id(mod));
-}
-
-static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi)
-{
-	struct rsnd_mod *mod = rsnd_mod_get(ssi);
-	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-	struct device *dev = rsnd_priv_to_dev(priv);
-	u32 cr;
-
-	if (0 == ssi->usrcnt) {
-		dev_err(dev, "%s called without starting\n", __func__);
-		return;
+	/*
+	 * TDM Extend Mode
+	 * see
+	 *	rsnd_ssiu_init_gen2()
+	 */
+	wsr = ssi->wsr;
+	if (is_tdm) {
+		wsr	|= WS_MODE;
+		cr_own	|= CHNL_8;
 	}
 
-	ssi->usrcnt--;
+	ssi->cr_own	= cr_own;
+	ssi->cr_mode	= cr_mode;
+	ssi->wsr	= wsr;
 
-	if (0 == ssi->usrcnt) {
-		/*
-		 * disable all IRQ,
-		 * and, wait all data was sent
-		 */
-		cr  =	ssi->cr_own	|
-			ssi->cr_clk;
-
-		rsnd_mod_write(mod, SSICR, cr | EN);
-		rsnd_ssi_status_check(mod, DIRQ);
-
-		/*
-		 * disable SSI,
-		 * and, wait idle state
-		 */
-		rsnd_mod_write(mod, SSICR, cr);	/* disabled all */
-		rsnd_ssi_status_check(mod, IIRQ);
-
-		if (rsnd_rdai_is_clk_master(rdai)) {
-			struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
-
-			if (ssi_parent)
-				rsnd_ssi_hw_stop(io, ssi_parent);
-			else
-				rsnd_ssi_master_clk_stop(ssi);
-		}
-
-		rsnd_mod_power_off(mod);
-
-		ssi->chan = 0;
-	}
-
-	dev_dbg(dev, "%s[%d] hw stopped\n",
-		rsnd_mod_name(mod), rsnd_mod_id(mod));
+	return 0;
 }
 
 /*
@@ -282,49 +369,30 @@
 			 struct rsnd_priv *priv)
 {
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-	u32 cr;
+	int ret;
 
-	cr = FORCE;
+	ssi->usrcnt++;
 
-	/*
-	 * always use 32bit system word for easy clock calculation.
-	 * see also rsnd_ssi_master_clk_enable()
-	 */
-	cr |= SWL_32;
+	rsnd_mod_power_on(mod);
 
-	/*
-	 * init clock settings for SSICR
-	 */
-	switch (runtime->sample_bits) {
-	case 16:
-		cr |= DWL_16;
-		break;
-	case 32:
-		cr |= DWL_24;
-		break;
-	default:
-		return -EIO;
-	}
+	ret = rsnd_ssi_master_clk_start(ssi, io);
+	if (ret < 0)
+		return ret;
 
-	if (rdai->bit_clk_inv)
-		cr |= SCKP;
-	if (rdai->frm_clk_inv)
-		cr |= SWSP;
-	if (rdai->data_alignment)
-		cr |= SDTA;
-	if (rdai->sys_delay)
-		cr |= DEL;
-	if (rsnd_io_is_play(io))
-		cr |= TRMD;
+	if (rsnd_ssi_is_parent(mod, io))
+		return 0;
 
-	/*
-	 * set ssi parameter
-	 */
-	ssi->cr_own	= cr;
+	ret = rsnd_ssi_config_init(ssi, io);
+	if (ret < 0)
+		return ret;
+
 	ssi->err	= -1; /* ignore 1st error */
 
+	/* clear error status */
+	rsnd_ssi_status_clear(mod);
+
+	rsnd_ssi_irq_enable(mod);
+
 	return 0;
 }
 
@@ -335,12 +403,29 @@
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 	struct device *dev = rsnd_priv_to_dev(priv);
 
-	if (ssi->err > 0)
-		dev_warn(dev, "%s[%d] under/over flow err = %d\n",
-			 rsnd_mod_name(mod), rsnd_mod_id(mod), ssi->err);
+	if (!ssi->usrcnt) {
+		dev_err(dev, "%s[%d] usrcnt error\n",
+			rsnd_mod_name(mod), rsnd_mod_id(mod));
+		return -EIO;
+	}
 
-	ssi->cr_own	= 0;
-	ssi->err	= 0;
+	if (!rsnd_ssi_is_parent(mod, io)) {
+		if (ssi->err > 0)
+			dev_warn(dev, "%s[%d] under/over flow err = %d\n",
+				 rsnd_mod_name(mod), rsnd_mod_id(mod),
+				 ssi->err);
+
+		ssi->cr_own	= 0;
+		ssi->err	= 0;
+
+		rsnd_ssi_irq_disable(mod);
+	}
+
+	rsnd_ssi_master_clk_stop(ssi, io);
+
+	rsnd_mod_power_off(mod);
+
+	ssi->usrcnt--;
 
 	return 0;
 }
@@ -351,14 +436,13 @@
 			      struct snd_pcm_hw_params *params)
 {
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-	struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
 	int chan = params_channels(params);
 
 	/*
 	 * Already working.
 	 * It will happen if SSI has parent/child connection.
 	 */
-	if (ssi->usrcnt) {
+	if (ssi->usrcnt > 1) {
 		/*
 		 * it is error if child <-> parent SSI uses
 		 * different channels.
@@ -367,39 +451,83 @@
 			return -EIO;
 	}
 
-	/* It will be removed on rsnd_ssi_hw_stop */
 	ssi->chan = chan;
-	if (ssi_parent)
-		return rsnd_ssi_hw_params(rsnd_mod_get(ssi_parent), io,
-					  substream, params);
 
 	return 0;
 }
 
-static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
+static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi)
 {
 	struct rsnd_mod *mod = rsnd_mod_get(ssi);
+	u32 status = rsnd_ssi_status_get(mod);
 
 	/* under/over flow error */
-	if (status & (UIRQ | OIRQ)) {
+	if (status & (UIRQ | OIRQ))
 		ssi->err++;
 
-		/* clear error status */
-		rsnd_mod_write(mod, SSISR, 0);
-	}
+	return status;
+}
+
+static int __rsnd_ssi_start(struct rsnd_mod *mod,
+			    struct rsnd_dai_stream *io,
+			    struct rsnd_priv *priv)
+{
+	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+	u32 cr;
+
+	cr  =	ssi->cr_own	|
+		ssi->cr_clk	|
+		ssi->cr_mode;
+
+	/*
+	 * EN will be set via SSIU :: SSI_CONTROL
+	 * if Multi channel mode
+	 */
+	if (!rsnd_ssi_multi_slaves(io))
+		cr |= EN;
+
+	rsnd_mod_write(mod, SSICR, cr);
+	rsnd_mod_write(mod, SSIWSR, ssi->wsr);
+
+	return 0;
 }
 
 static int rsnd_ssi_start(struct rsnd_mod *mod,
 			  struct rsnd_dai_stream *io,
 			  struct rsnd_priv *priv)
 {
+	/*
+	 * no limit to start
+	 * see also
+	 *	rsnd_ssi_stop
+	 *	rsnd_ssi_interrupt
+	 */
+	return __rsnd_ssi_start(mod, io, priv);
+}
+
+static int __rsnd_ssi_stop(struct rsnd_mod *mod,
+			   struct rsnd_dai_stream *io,
+			   struct rsnd_priv *priv)
+{
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+	u32 cr;
 
-	rsnd_src_ssiu_start(mod, io, rsnd_ssi_use_busif(io));
+	/*
+	 * disable all IRQ,
+	 * and, wait all data was sent
+	 */
+	cr  =	ssi->cr_own	|
+		ssi->cr_clk;
 
-	rsnd_ssi_hw_start(ssi, io);
+	rsnd_mod_write(mod, SSICR, cr | EN);
+	rsnd_ssi_status_check(mod, DIRQ);
 
-	rsnd_src_ssi_irq_enable(mod);
+	/*
+	 * disable SSI,
+	 * and, wait idle state
+	 */
+	rsnd_mod_write(mod, SSICR, cr);	/* disabled all */
+	rsnd_ssi_status_check(mod, IIRQ);
 
 	return 0;
 }
@@ -410,15 +538,16 @@
 {
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 
-	rsnd_src_ssi_irq_disable(mod);
+	/*
+	 * don't stop if not last user
+	 * see also
+	 *	rsnd_ssi_start
+	 *	rsnd_ssi_interrupt
+	 */
+	if (ssi->usrcnt > 1)
+		return 0;
 
-	rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR));
-
-	rsnd_ssi_hw_stop(io, ssi);
-
-	rsnd_src_ssiu_stop(mod, io);
-
-	return 0;
+	return __rsnd_ssi_stop(mod, io, priv);
 }
 
 static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
@@ -426,6 +555,7 @@
 {
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
 	int is_dma = rsnd_ssi_is_dma_mode(mod);
 	u32 status;
 	bool elapsed = false;
@@ -436,7 +566,7 @@
 	if (!rsnd_io_is_working(io))
 		goto rsnd_ssi_interrupt_out;
 
-	status = rsnd_mod_read(mod, SSISR);
+	status = rsnd_ssi_record_error(ssi);
 
 	/* PIO only */
 	if (!is_dma && (status & DIRQ)) {
@@ -459,23 +589,24 @@
 
 	/* DMA only */
 	if (is_dma && (status & (UIRQ | OIRQ))) {
-		struct device *dev = rsnd_priv_to_dev(priv);
-
 		/*
 		 * restart SSI
 		 */
 		dev_dbg(dev, "%s[%d] restart\n",
 			rsnd_mod_name(mod), rsnd_mod_id(mod));
 
-		rsnd_ssi_stop(mod, io, priv);
-		if (ssi->err < 1024)
-			rsnd_ssi_start(mod, io, priv);
-		else
-			dev_warn(dev, "no more SSI restart\n");
+		__rsnd_ssi_stop(mod, io, priv);
+		__rsnd_ssi_start(mod, io, priv);
 	}
 
-	rsnd_ssi_record_error(ssi, status);
+	if (ssi->err > 1024) {
+		rsnd_ssi_irq_disable(mod);
 
+		dev_warn(dev, "no more %s[%d] restart\n",
+			 rsnd_mod_name(mod), rsnd_mod_id(mod));
+	}
+
+	rsnd_ssi_status_clear(mod);
 rsnd_ssi_interrupt_out:
 	spin_unlock(&priv->lock);
 
@@ -495,15 +626,49 @@
 /*
  *		SSI PIO
  */
-static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
-			      struct rsnd_dai_stream *io,
-			      struct rsnd_priv *priv)
+static void rsnd_ssi_parent_attach(struct rsnd_mod *mod,
+				   struct rsnd_dai_stream *io,
+				   struct rsnd_priv *priv)
+{
+	if (!__rsnd_ssi_is_pin_sharing(mod))
+		return;
+
+	switch (rsnd_mod_id(mod)) {
+	case 1:
+	case 2:
+		rsnd_dai_connect(rsnd_ssi_mod_get(priv, 0), io, RSND_MOD_SSIP);
+		break;
+	case 4:
+		rsnd_dai_connect(rsnd_ssi_mod_get(priv, 3), io, RSND_MOD_SSIP);
+		break;
+	case 8:
+		rsnd_dai_connect(rsnd_ssi_mod_get(priv, 7), io, RSND_MOD_SSIP);
+		break;
+	}
+}
+
+static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
+				 struct rsnd_dai_stream *io,
+				 struct rsnd_priv *priv)
 {
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 	int ret;
 
-	ret = devm_request_irq(dev, ssi->info->irq,
+	/*
+	 * SSIP/SSIU/IRQ are not needed on
+	 * SSI Multi slaves
+	 */
+	if (rsnd_ssi_is_multi_slave(mod, io))
+		return 0;
+
+	rsnd_ssi_parent_attach(mod, io, priv);
+
+	ret = rsnd_ssiu_attach(io, mod);
+	if (ret < 0)
+		return ret;
+
+	ret = devm_request_irq(dev, ssi->irq,
 			       rsnd_ssi_interrupt,
 			       IRQF_SHARED,
 			       dev_name(dev), mod);
@@ -513,7 +678,7 @@
 
 static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
 	.name	= SSI_NAME,
-	.probe	= rsnd_ssi_pio_probe,
+	.probe	= rsnd_ssi_common_probe,
 	.init	= rsnd_ssi_init,
 	.quit	= rsnd_ssi_quit,
 	.start	= rsnd_ssi_start,
@@ -526,20 +691,23 @@
 			      struct rsnd_priv *priv)
 {
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-	struct device *dev = rsnd_priv_to_dev(priv);
-	int dma_id = ssi->info->dma_id;
+	int dma_id = 0; /* not needed */
 	int ret;
 
-	ret = devm_request_irq(dev, ssi->info->irq,
-			       rsnd_ssi_interrupt,
-			       IRQF_SHARED,
-			       dev_name(dev), mod);
+	/*
+	 * SSIP/SSIU/IRQ/DMA are not needed on
+	 * SSI Multi slaves
+	 */
+	if (rsnd_ssi_is_multi_slave(mod, io))
+		return 0;
+
+	ret = rsnd_ssi_common_probe(mod, io, priv);
 	if (ret)
 		return ret;
 
-	ret = rsnd_dma_init(
-		io, rsnd_mod_to_dma(mod),
-		dma_id);
+	ssi->dma = rsnd_dma_attach(io, mod, dma_id);
+	if (IS_ERR(ssi->dma))
+		return PTR_ERR(ssi->dma);
 
 	return ret;
 }
@@ -550,9 +718,7 @@
 {
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 	struct device *dev = rsnd_priv_to_dev(priv);
-	int irq = ssi->info->irq;
-
-	rsnd_dma_quit(io, rsnd_mod_to_dma(mod));
+	int irq = ssi->irq;
 
 	/* PIO will request IRQ again */
 	devm_free_irq(dev, irq, mod);
@@ -581,32 +747,6 @@
 	return 0;
 }
 
-static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
-			      struct rsnd_dai_stream *io,
-			      struct rsnd_priv *priv)
-{
-	struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
-
-	rsnd_dma_start(io, dma);
-
-	rsnd_ssi_start(mod, io, priv);
-
-	return 0;
-}
-
-static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
-			     struct rsnd_dai_stream *io,
-			     struct rsnd_priv *priv)
-{
-	struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
-
-	rsnd_ssi_stop(mod, io, priv);
-
-	rsnd_dma_stop(io, dma);
-
-	return 0;
-}
-
 static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
 					 struct rsnd_mod *mod)
 {
@@ -630,8 +770,8 @@
 	.remove	= rsnd_ssi_dma_remove,
 	.init	= rsnd_ssi_init,
 	.quit	= rsnd_ssi_quit,
-	.start	= rsnd_ssi_dma_start,
-	.stop	= rsnd_ssi_dma_stop,
+	.start	= rsnd_ssi_start,
+	.stop	= rsnd_ssi_stop,
 	.fallback = rsnd_ssi_fallback,
 	.hw_params = rsnd_ssi_hw_params,
 };
@@ -652,12 +792,63 @@
 /*
  *		ssi mod function
  */
+static void rsnd_ssi_connect(struct rsnd_mod *mod,
+			     struct rsnd_dai_stream *io)
+{
+	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+	enum rsnd_mod_type types[] = {
+		RSND_MOD_SSI,
+		RSND_MOD_SSIM1,
+		RSND_MOD_SSIM2,
+		RSND_MOD_SSIM3,
+	};
+	enum rsnd_mod_type type;
+	int i;
+
+	/* try SSI -> SSIM1 -> SSIM2 -> SSIM3 */
+	for (i = 0; i < ARRAY_SIZE(types); i++) {
+		type = types[i];
+		if (!rsnd_io_to_mod(io, type)) {
+			rsnd_dai_connect(mod, io, type);
+			rsnd_set_slot(rdai, 2 * (i + 1), (i + 1));
+			return;
+		}
+	}
+}
+
+void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
+			    struct device_node *playback,
+			    struct device_node *capture)
+{
+	struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+	struct device_node *node;
+	struct device_node *np;
+	struct rsnd_mod *mod;
+	int i;
+
+	node = rsnd_ssi_of_node(priv);
+	if (!node)
+		return;
+
+	i = 0;
+	for_each_child_of_node(node, np) {
+		mod = rsnd_ssi_mod_get(priv, i);
+		if (np == playback)
+			rsnd_ssi_connect(mod, &rdai->playback);
+		if (np == capture)
+			rsnd_ssi_connect(mod, &rdai->capture);
+		i++;
+	}
+
+	of_node_put(node);
+}
+
 struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
 {
 	if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
 		id = 0;
 
-	return rsnd_mod_get((struct rsnd_ssi *)(priv->ssi) + id);
+	return rsnd_mod_get(rsnd_ssi_get(priv, id));
 }
 
 int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
@@ -667,95 +858,10 @@
 	return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
 }
 
-static void rsnd_ssi_parent_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi)
-{
-	struct rsnd_mod *mod = rsnd_mod_get(ssi);
-
-	if (!__rsnd_ssi_is_pin_sharing(mod))
-		return;
-
-	switch (rsnd_mod_id(mod)) {
-	case 1:
-	case 2:
-		ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 0));
-		break;
-	case 4:
-		ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 3));
-		break;
-	case 8:
-		ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 7));
-		break;
-	}
-}
-
-
-static void rsnd_of_parse_ssi(struct platform_device *pdev,
-			      const struct rsnd_of_data *of_data,
-			      struct rsnd_priv *priv)
+int rsnd_ssi_probe(struct rsnd_priv *priv)
 {
 	struct device_node *node;
 	struct device_node *np;
-	struct rsnd_ssi_platform_info *ssi_info;
-	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-	struct device *dev = &pdev->dev;
-	int nr, i;
-
-	node = rsnd_ssi_of_node(priv);
-	if (!node)
-		return;
-
-	nr = of_get_child_count(node);
-	if (!nr)
-		goto rsnd_of_parse_ssi_end;
-
-	ssi_info = devm_kzalloc(dev,
-				sizeof(struct rsnd_ssi_platform_info) * nr,
-				GFP_KERNEL);
-	if (!ssi_info) {
-		dev_err(dev, "ssi info allocation error\n");
-		goto rsnd_of_parse_ssi_end;
-	}
-
-	info->ssi_info		= ssi_info;
-	info->ssi_info_nr	= nr;
-
-	i = -1;
-	for_each_child_of_node(node, np) {
-		i++;
-
-		ssi_info = info->ssi_info + i;
-
-		/*
-		 * pin settings
-		 */
-		if (of_get_property(np, "shared-pin", NULL))
-			ssi_info->flags |= RSND_SSI_CLK_PIN_SHARE;
-
-		/*
-		 * irq
-		 */
-		ssi_info->irq = irq_of_parse_and_map(np, 0);
-
-		/*
-		 * DMA
-		 */
-		ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ?
-			0 : 1;
-
-		if (of_get_property(np, "no-busif", NULL))
-			ssi_info->flags |= RSND_SSI_NO_BUSIF;
-	}
-
-rsnd_of_parse_ssi_end:
-	of_node_put(node);
-}
-
-int rsnd_ssi_probe(struct platform_device *pdev,
-		   const struct rsnd_of_data *of_data,
-		   struct rsnd_priv *priv)
-{
-	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-	struct rsnd_ssi_platform_info *pinfo;
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_mod_ops *ops;
 	struct clk *clk;
@@ -763,50 +869,73 @@
 	char name[RSND_SSI_NAME_SIZE];
 	int i, nr, ret;
 
-	rsnd_of_parse_ssi(pdev, of_data, priv);
+	node = rsnd_ssi_of_node(priv);
+	if (!node)
+		return -EINVAL;
 
-	/*
-	 *	init SSI
-	 */
-	nr	= info->ssi_info_nr;
+	nr = of_get_child_count(node);
+	if (!nr) {
+		ret = -EINVAL;
+		goto rsnd_ssi_probe_done;
+	}
+
 	ssi	= devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL);
-	if (!ssi)
-		return -ENOMEM;
+	if (!ssi) {
+		ret = -ENOMEM;
+		goto rsnd_ssi_probe_done;
+	}
 
 	priv->ssi	= ssi;
 	priv->ssi_nr	= nr;
 
-	for_each_rsnd_ssi(ssi, priv, i) {
-		pinfo = &info->ssi_info[i];
+	i = 0;
+	for_each_child_of_node(node, np) {
+		ssi = rsnd_ssi_get(priv, i);
 
 		snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d",
 			 SSI_NAME, i);
 
 		clk = devm_clk_get(dev, name);
-		if (IS_ERR(clk))
-			return PTR_ERR(clk);
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			goto rsnd_ssi_probe_done;
+		}
 
-		ssi->info	= pinfo;
+		if (of_get_property(np, "shared-pin", NULL))
+			ssi->flags |= RSND_SSI_CLK_PIN_SHARE;
+
+		if (of_get_property(np, "no-busif", NULL))
+			ssi->flags |= RSND_SSI_NO_BUSIF;
+
+		ssi->irq = irq_of_parse_and_map(np, 0);
+		if (!ssi->irq) {
+			ret = -EINVAL;
+			goto rsnd_ssi_probe_done;
+		}
 
 		ops = &rsnd_ssi_non_ops;
-		if (pinfo->dma_id > 0)
-			ops = &rsnd_ssi_dma_ops;
-		else if (rsnd_ssi_pio_available(ssi))
+		if (of_get_property(np, "pio-transfer", NULL))
 			ops = &rsnd_ssi_pio_ops;
+		else
+			ops = &rsnd_ssi_dma_ops;
 
 		ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
 				    RSND_MOD_SSI, i);
 		if (ret)
-			return ret;
+			goto rsnd_ssi_probe_done;
 
-		rsnd_ssi_parent_setup(priv, ssi);
+		i++;
 	}
 
-	return 0;
+	ret = 0;
+
+rsnd_ssi_probe_done:
+	of_node_put(node);
+
+	return ret;
 }
 
-void rsnd_ssi_remove(struct platform_device *pdev,
-		     struct rsnd_priv *priv)
+void rsnd_ssi_remove(struct rsnd_priv *priv)
 {
 	struct rsnd_ssi *ssi;
 	int i;
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
new file mode 100644
index 0000000..06d7282
--- /dev/null
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -0,0 +1,225 @@
+/*
+ * Renesas R-Car SSIU support
+ *
+ * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 "rsnd.h"
+
+#define SSIU_NAME "ssiu"
+
+struct rsnd_ssiu {
+	struct rsnd_mod mod;
+};
+
+#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
+#define for_each_rsnd_ssiu(pos, priv, i)				\
+	for (i = 0;							\
+	     (i < rsnd_ssiu_nr(priv)) &&				\
+		     ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i));	\
+	     i++)
+
+static int rsnd_ssiu_init(struct rsnd_mod *mod,
+			  struct rsnd_dai_stream *io,
+			  struct rsnd_priv *priv)
+{
+	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+	u32 multi_ssi_slaves = rsnd_ssi_multi_slaves(io);
+	int use_busif = rsnd_ssi_use_busif(io);
+	int id = rsnd_mod_id(mod);
+	u32 mask1, val1;
+	u32 mask2, val2;
+
+	/*
+	 * SSI_MODE0
+	 */
+	rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
+
+	/*
+	 * SSI_MODE1
+	 */
+	mask1 = (1 << 4) | (1 << 20);	/* mask sync bit */
+	mask2 = (1 << 4);		/* mask sync bit */
+	val1  = val2  = 0;
+	if (rsnd_ssi_is_pin_sharing(io)) {
+		int shift = -1;
+
+		switch (id) {
+		case 1:
+			shift = 0;
+			break;
+		case 2:
+			shift = 2;
+			break;
+		case 4:
+			shift = 16;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		mask1 |= 0x3 << shift;
+		val1 = rsnd_rdai_is_clk_master(rdai) ?
+			0x2 << shift : 0x1 << shift;
+
+	} else if (multi_ssi_slaves) {
+
+		mask2 |= 0x00000007;
+		mask1 |= 0x0000000f;
+
+		switch (multi_ssi_slaves) {
+		case 0x0206: /* SSI0/1/2/9 */
+			val2 = (1 << 4) | /* SSI0129 sync */
+				(rsnd_rdai_is_clk_master(rdai) ? 0x2 : 0x1);
+			/* fall through */
+		case 0x0006: /* SSI0/1/2 */
+			val1 = rsnd_rdai_is_clk_master(rdai) ?
+				0xa : 0x5;
+
+			if (!val2)  /* SSI012 sync */
+				val1 |= (1 << 4);
+		}
+	}
+
+	rsnd_mod_bset(mod, SSI_MODE1, mask1, val1);
+	rsnd_mod_bset(mod, SSI_MODE2, mask2, val2);
+
+	return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
+	.name	= SSIU_NAME,
+	.init	= rsnd_ssiu_init,
+};
+
+static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
+			       struct rsnd_dai_stream *io,
+			       struct rsnd_priv *priv)
+{
+	int ret;
+
+	ret = rsnd_ssiu_init(mod, io, priv);
+	if (ret < 0)
+		return ret;
+
+	if (rsnd_get_slot_width(io) >= 6) {
+		/*
+		 * TDM Extend Mode
+		 * see
+		 *	rsnd_ssi_config_init()
+		 */
+		rsnd_mod_write(mod, SSI_MODE, 0x1);
+	}
+
+	if (rsnd_ssi_use_busif(io)) {
+		u32 val = rsnd_get_dalign(mod, io);
+
+		rsnd_mod_write(mod, SSI_BUSIF_ADINR,
+			       rsnd_get_adinr_bit(mod, io) |
+			       rsnd_get_adinr_chan(mod, io));
+		rsnd_mod_write(mod, SSI_BUSIF_MODE,  1);
+		rsnd_mod_write(mod, SSI_BUSIF_DALIGN, val);
+	}
+
+	return 0;
+}
+
+static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
+				struct rsnd_dai_stream *io,
+				struct rsnd_priv *priv)
+{
+	if (!rsnd_ssi_use_busif(io))
+		return 0;
+
+	rsnd_mod_write(mod, SSI_CTRL, 0x1);
+
+	if (rsnd_ssi_multi_slaves(io))
+		rsnd_mod_write(mod, SSI_CONTROL, 0x1);
+
+	return 0;
+}
+
+static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
+			       struct rsnd_dai_stream *io,
+			       struct rsnd_priv *priv)
+{
+	if (!rsnd_ssi_use_busif(io))
+		return 0;
+
+	rsnd_mod_write(mod, SSI_CTRL, 0);
+
+	if (rsnd_ssi_multi_slaves(io))
+		rsnd_mod_write(mod, SSI_CONTROL, 0);
+
+	return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
+	.name	= SSIU_NAME,
+	.init	= rsnd_ssiu_init_gen2,
+	.start	= rsnd_ssiu_start_gen2,
+	.stop	= rsnd_ssiu_stop_gen2,
+};
+
+static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
+{
+	if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
+		id = 0;
+
+	return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
+}
+
+int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
+		     struct rsnd_mod *ssi_mod)
+{
+	struct rsnd_priv *priv = rsnd_io_to_priv(io);
+	struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod));
+
+	rsnd_mod_confirm_ssi(ssi_mod);
+
+	return rsnd_dai_connect(mod, io, mod->type);
+}
+
+int rsnd_ssiu_probe(struct rsnd_priv *priv)
+{
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct rsnd_ssiu *ssiu;
+	static struct rsnd_mod_ops *ops;
+	int i, nr, ret;
+
+	/* same number to SSI */
+	nr	= priv->ssi_nr;
+	ssiu	= devm_kzalloc(dev, sizeof(*ssiu) * nr, GFP_KERNEL);
+	if (!ssiu)
+		return -ENOMEM;
+
+	priv->ssiu	= ssiu;
+	priv->ssiu_nr	= nr;
+
+	if (rsnd_is_gen1(priv))
+		ops = &rsnd_ssiu_ops_gen1;
+	else
+		ops = &rsnd_ssiu_ops_gen2;
+
+	for_each_rsnd_ssiu(ssiu, priv, i) {
+		ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
+				    ops, NULL, RSND_MOD_SSIU, i);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+void rsnd_ssiu_remove(struct rsnd_priv *priv)
+{
+	struct rsnd_ssiu *ssiu;
+	int i;
+
+	for_each_rsnd_ssiu(ssiu, priv, i) {
+		rsnd_mod_quit(rsnd_mod_get(ssiu));
+	}
+}
diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c
index d40efc9..7e0acd8 100644
--- a/sound/soc/soc-ac97.c
+++ b/sound/soc/soc-ac97.c
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/init.h>
 #include <linux/of_gpio.h>
 #include <linux/of.h>
@@ -38,6 +39,14 @@
 	int gpio_reset;
 };
 
+struct snd_ac97_gpio_priv {
+#ifdef CONFIG_GPIOLIB
+	struct gpio_chip gpio_chip;
+#endif
+	unsigned int gpios_set;
+	struct snd_soc_codec *codec;
+};
+
 static struct snd_ac97_bus soc_ac97_bus = {
 	.ops = NULL, /* Gets initialized in snd_soc_set_ac97_ops() */
 };
@@ -47,6 +56,117 @@
 	kfree(to_ac97_t(dev));
 }
 
+#ifdef CONFIG_GPIOLIB
+static inline struct snd_soc_codec *gpio_to_codec(struct gpio_chip *chip)
+{
+	struct snd_ac97_gpio_priv *gpio_priv =
+		container_of(chip, struct snd_ac97_gpio_priv, gpio_chip);
+
+	return gpio_priv->codec;
+}
+
+static int snd_soc_ac97_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	if (offset >= AC97_NUM_GPIOS)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int snd_soc_ac97_gpio_direction_in(struct gpio_chip *chip,
+					  unsigned offset)
+{
+	struct snd_soc_codec *codec = gpio_to_codec(chip);
+
+	dev_dbg(codec->dev, "set gpio %d to output\n", offset);
+	return snd_soc_update_bits(codec, AC97_GPIO_CFG,
+				   1 << offset, 1 << offset);
+}
+
+static int snd_soc_ac97_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct snd_soc_codec *codec = gpio_to_codec(chip);
+	int ret;
+
+	ret = snd_soc_read(codec, AC97_GPIO_STATUS);
+	dev_dbg(codec->dev, "get gpio %d : %d\n", offset,
+		ret < 0 ? ret : ret & (1 << offset));
+
+	return ret < 0 ? ret : !!(ret & (1 << offset));
+}
+
+static void snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned offset,
+				  int value)
+{
+	struct snd_ac97_gpio_priv *gpio_priv =
+		container_of(chip, struct snd_ac97_gpio_priv, gpio_chip);
+	struct snd_soc_codec *codec = gpio_to_codec(chip);
+
+	gpio_priv->gpios_set &= ~(1 << offset);
+	gpio_priv->gpios_set |= (!!value) << offset;
+	snd_soc_write(codec, AC97_GPIO_STATUS, gpio_priv->gpios_set);
+	dev_dbg(codec->dev, "set gpio %d to %d\n", offset, !!value);
+}
+
+static int snd_soc_ac97_gpio_direction_out(struct gpio_chip *chip,
+				     unsigned offset, int value)
+{
+	struct snd_soc_codec *codec = gpio_to_codec(chip);
+
+	dev_dbg(codec->dev, "set gpio %d to output\n", offset);
+	snd_soc_ac97_gpio_set(chip, offset, value);
+	return snd_soc_update_bits(codec, AC97_GPIO_CFG, 1 << offset, 0);
+}
+
+static struct gpio_chip snd_soc_ac97_gpio_chip = {
+	.label			= "snd_soc_ac97",
+	.owner			= THIS_MODULE,
+	.request		= snd_soc_ac97_gpio_request,
+	.direction_input	= snd_soc_ac97_gpio_direction_in,
+	.get			= snd_soc_ac97_gpio_get,
+	.direction_output	= snd_soc_ac97_gpio_direction_out,
+	.set			= snd_soc_ac97_gpio_set,
+	.can_sleep		= 1,
+};
+
+static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97,
+				  struct snd_soc_codec *codec)
+{
+	struct snd_ac97_gpio_priv *gpio_priv;
+	int ret;
+
+	gpio_priv = devm_kzalloc(codec->dev, sizeof(*gpio_priv), GFP_KERNEL);
+	if (!gpio_priv)
+		return -ENOMEM;
+	ac97->gpio_priv = gpio_priv;
+	gpio_priv->codec = codec;
+	gpio_priv->gpio_chip = snd_soc_ac97_gpio_chip;
+	gpio_priv->gpio_chip.ngpio = AC97_NUM_GPIOS;
+	gpio_priv->gpio_chip.parent = codec->dev;
+	gpio_priv->gpio_chip.base = -1;
+
+	ret = gpiochip_add(&gpio_priv->gpio_chip);
+	if (ret != 0)
+		dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+	return ret;
+}
+
+static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97)
+{
+	gpiochip_remove(&ac97->gpio_priv->gpio_chip);
+}
+#else
+static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97,
+				  struct snd_soc_codec *codec)
+{
+	return 0;
+}
+
+static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97)
+{
+}
+#endif
+
 /**
  * snd_soc_alloc_ac97_codec() - Allocate new a AC'97 device
  * @codec: The CODEC for which to create the AC'97 device
@@ -119,6 +239,10 @@
 	if (ret)
 		goto err_put_device;
 
+	ret = snd_soc_ac97_init_gpio(ac97, codec);
+	if (ret)
+		goto err_put_device;
+
 	return ac97;
 
 err_put_device:
@@ -135,6 +259,7 @@
  */
 void snd_soc_free_ac97_codec(struct snd_ac97 *ac97)
 {
+	snd_soc_ac97_free_gpio(ac97);
 	device_del(&ac97->dev);
 	ac97->bus = NULL;
 	put_device(&ac97->dev);
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 12a9820..875733c 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -630,6 +630,7 @@
 	struct snd_pcm *be_pcm;
 	char new_name[64];
 	int ret = 0, direction = 0;
+	int playback = 0, capture = 0;
 
 	if (rtd->num_codecs > 1) {
 		dev_err(rtd->card->dev, "Multicodec not supported for compressed stream\n");
@@ -641,11 +642,27 @@
 			rtd->dai_link->stream_name, codec_dai->name, num);
 
 	if (codec_dai->driver->playback.channels_min)
-		direction = SND_COMPRESS_PLAYBACK;
-	else if (codec_dai->driver->capture.channels_min)
-		direction = SND_COMPRESS_CAPTURE;
-	else
+		playback = 1;
+	if (codec_dai->driver->capture.channels_min)
+		capture = 1;
+
+	capture = capture && cpu_dai->driver->capture.channels_min;
+	playback = playback && cpu_dai->driver->playback.channels_min;
+
+	/*
+	 * Compress devices are unidirectional so only one of the directions
+	 * should be set, check for that (xor)
+	 */
+	if (playback + capture != 1) {
+		dev_err(rtd->card->dev, "Invalid direction for compress P %d, C %d\n",
+				playback, capture);
 		return -EINVAL;
+	}
+
+	if(playback)
+		direction = SND_COMPRESS_PLAYBACK;
+	else
+		direction = SND_COMPRESS_CAPTURE;
 
 	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
 	if (compr == NULL) {
@@ -689,7 +706,13 @@
 		compr->ops->copy = soc_compr_copy;
 
 	mutex_init(&compr->lock);
-	ret = snd_compress_new(rtd->card->snd_card, num, direction, compr);
+
+	snprintf(new_name, sizeof(new_name), "%s %s-%d",
+		 rtd->dai_link->stream_name,
+		 rtd->codec_dai->name, num);
+
+	ret = snd_compress_new(rtd->card->snd_card, num, direction,
+				new_name, compr);
 	if (ret < 0) {
 		pr_err("compress asoc: can't create compress for codec %s\n",
 			codec->component.name);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index a1305f8..790ee2b 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -537,26 +537,75 @@
 struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
 		const char *dai_link, int stream)
 {
-	int i;
+	struct snd_soc_pcm_runtime *rtd;
 
-	for (i = 0; i < card->num_links; i++) {
-		if (card->rtd[i].dai_link->no_pcm &&
-			!strcmp(card->rtd[i].dai_link->name, dai_link))
-			return card->rtd[i].pcm->streams[stream].substream;
+	list_for_each_entry(rtd, &card->rtd_list, list) {
+		if (rtd->dai_link->no_pcm &&
+			!strcmp(rtd->dai_link->name, dai_link))
+			return rtd->pcm->streams[stream].substream;
 	}
 	dev_dbg(card->dev, "ASoC: failed to find dai link %s\n", dai_link);
 	return NULL;
 }
 EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream);
 
+static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
+	struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
+{
+	struct snd_soc_pcm_runtime *rtd;
+
+	rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL);
+	if (!rtd)
+		return NULL;
+
+	rtd->card = card;
+	rtd->dai_link = dai_link;
+	rtd->codec_dais = kzalloc(sizeof(struct snd_soc_dai *) *
+					dai_link->num_codecs,
+					GFP_KERNEL);
+	if (!rtd->codec_dais) {
+		kfree(rtd);
+		return NULL;
+	}
+
+	return rtd;
+}
+
+static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
+{
+	if (rtd && rtd->codec_dais)
+		kfree(rtd->codec_dais);
+	kfree(rtd);
+}
+
+static void soc_add_pcm_runtime(struct snd_soc_card *card,
+		struct snd_soc_pcm_runtime *rtd)
+{
+	list_add_tail(&rtd->list, &card->rtd_list);
+	rtd->num = card->num_rtd;
+	card->num_rtd++;
+}
+
+static void soc_remove_pcm_runtimes(struct snd_soc_card *card)
+{
+	struct snd_soc_pcm_runtime *rtd, *_rtd;
+
+	list_for_each_entry_safe(rtd, _rtd, &card->rtd_list, list) {
+		list_del(&rtd->list);
+		soc_free_pcm_runtime(rtd);
+	}
+
+	card->num_rtd = 0;
+}
+
 struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
 		const char *dai_link)
 {
-	int i;
+	struct snd_soc_pcm_runtime *rtd;
 
-	for (i = 0; i < card->num_links; i++) {
-		if (!strcmp(card->rtd[i].dai_link->name, dai_link))
-			return &card->rtd[i];
+	list_for_each_entry(rtd, &card->rtd_list, list) {
+		if (!strcmp(rtd->dai_link->name, dai_link))
+			return rtd;
 	}
 	dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link);
 	return NULL;
@@ -578,7 +627,8 @@
 {
 	struct snd_soc_card *card = dev_get_drvdata(dev);
 	struct snd_soc_codec *codec;
-	int i, j;
+	struct snd_soc_pcm_runtime *rtd;
+	int i;
 
 	/* If the card is not initialized yet there is nothing to do */
 	if (!card->instantiated)
@@ -595,13 +645,13 @@
 	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
 
 	/* mute any active DACs */
-	for (i = 0; i < card->num_rtd; i++) {
+	list_for_each_entry(rtd, &card->rtd_list, list) {
 
-		if (card->rtd[i].dai_link->ignore_suspend)
+		if (rtd->dai_link->ignore_suspend)
 			continue;
 
-		for (j = 0; j < card->rtd[i].num_codecs; j++) {
-			struct snd_soc_dai *dai = card->rtd[i].codec_dais[j];
+		for (i = 0; i < rtd->num_codecs; i++) {
+			struct snd_soc_dai *dai = rtd->codec_dais[i];
 			struct snd_soc_dai_driver *drv = dai->driver;
 
 			if (drv->ops->digital_mute && dai->playback_active)
@@ -610,20 +660,20 @@
 	}
 
 	/* suspend all pcms */
-	for (i = 0; i < card->num_rtd; i++) {
-		if (card->rtd[i].dai_link->ignore_suspend)
+	list_for_each_entry(rtd, &card->rtd_list, list) {
+		if (rtd->dai_link->ignore_suspend)
 			continue;
 
-		snd_pcm_suspend_all(card->rtd[i].pcm);
+		snd_pcm_suspend_all(rtd->pcm);
 	}
 
 	if (card->suspend_pre)
 		card->suspend_pre(card);
 
-	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+	list_for_each_entry(rtd, &card->rtd_list, list) {
+		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
-		if (card->rtd[i].dai_link->ignore_suspend)
+		if (rtd->dai_link->ignore_suspend)
 			continue;
 
 		if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control)
@@ -631,19 +681,19 @@
 	}
 
 	/* close any waiting streams */
-	for (i = 0; i < card->num_rtd; i++)
-		flush_delayed_work(&card->rtd[i].delayed_work);
+	list_for_each_entry(rtd, &card->rtd_list, list)
+		flush_delayed_work(&rtd->delayed_work);
 
-	for (i = 0; i < card->num_rtd; i++) {
+	list_for_each_entry(rtd, &card->rtd_list, list) {
 
-		if (card->rtd[i].dai_link->ignore_suspend)
+		if (rtd->dai_link->ignore_suspend)
 			continue;
 
-		snd_soc_dapm_stream_event(&card->rtd[i],
+		snd_soc_dapm_stream_event(rtd,
 					  SNDRV_PCM_STREAM_PLAYBACK,
 					  SND_SOC_DAPM_STREAM_SUSPEND);
 
-		snd_soc_dapm_stream_event(&card->rtd[i],
+		snd_soc_dapm_stream_event(rtd,
 					  SNDRV_PCM_STREAM_CAPTURE,
 					  SND_SOC_DAPM_STREAM_SUSPEND);
 	}
@@ -690,10 +740,10 @@
 		}
 	}
 
-	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+	list_for_each_entry(rtd, &card->rtd_list, list) {
+		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
-		if (card->rtd[i].dai_link->ignore_suspend)
+		if (rtd->dai_link->ignore_suspend)
 			continue;
 
 		if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control)
@@ -717,8 +767,9 @@
 {
 	struct snd_soc_card *card =
 			container_of(work, struct snd_soc_card, deferred_resume_work);
+	struct snd_soc_pcm_runtime *rtd;
 	struct snd_soc_codec *codec;
-	int i, j;
+	int i;
 
 	/* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
 	 * so userspace apps are blocked from touching us
@@ -733,10 +784,10 @@
 		card->resume_pre(card);
 
 	/* resume control bus DAIs */
-	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+	list_for_each_entry(rtd, &card->rtd_list, list) {
+		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
-		if (card->rtd[i].dai_link->ignore_suspend)
+		if (rtd->dai_link->ignore_suspend)
 			continue;
 
 		if (cpu_dai->driver->resume && cpu_dai->driver->bus_control)
@@ -751,28 +802,28 @@
 		}
 	}
 
-	for (i = 0; i < card->num_rtd; i++) {
+	list_for_each_entry(rtd, &card->rtd_list, list) {
 
-		if (card->rtd[i].dai_link->ignore_suspend)
+		if (rtd->dai_link->ignore_suspend)
 			continue;
 
-		snd_soc_dapm_stream_event(&card->rtd[i],
+		snd_soc_dapm_stream_event(rtd,
 					  SNDRV_PCM_STREAM_PLAYBACK,
 					  SND_SOC_DAPM_STREAM_RESUME);
 
-		snd_soc_dapm_stream_event(&card->rtd[i],
+		snd_soc_dapm_stream_event(rtd,
 					  SNDRV_PCM_STREAM_CAPTURE,
 					  SND_SOC_DAPM_STREAM_RESUME);
 	}
 
 	/* unmute any active DACs */
-	for (i = 0; i < card->num_rtd; i++) {
+	list_for_each_entry(rtd, &card->rtd_list, list) {
 
-		if (card->rtd[i].dai_link->ignore_suspend)
+		if (rtd->dai_link->ignore_suspend)
 			continue;
 
-		for (j = 0; j < card->rtd[i].num_codecs; j++) {
-			struct snd_soc_dai *dai = card->rtd[i].codec_dais[j];
+		for (i = 0; i < rtd->num_codecs; i++) {
+			struct snd_soc_dai *dai = rtd->codec_dais[i];
 			struct snd_soc_dai_driver *drv = dai->driver;
 
 			if (drv->ops->digital_mute && dai->playback_active)
@@ -780,10 +831,10 @@
 		}
 	}
 
-	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+	list_for_each_entry(rtd, &card->rtd_list, list) {
+		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
-		if (card->rtd[i].dai_link->ignore_suspend)
+		if (rtd->dai_link->ignore_suspend)
 			continue;
 
 		if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control)
@@ -808,15 +859,14 @@
 {
 	struct snd_soc_card *card = dev_get_drvdata(dev);
 	bool bus_control = false;
-	int i;
+	struct snd_soc_pcm_runtime *rtd;
 
 	/* If the card is not initialized yet there is nothing to do */
 	if (!card->instantiated)
 		return 0;
 
 	/* activate pins from sleep state */
-	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+	list_for_each_entry(rtd, &card->rtd_list, list) {
 		struct snd_soc_dai **codec_dais = rtd->codec_dais;
 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 		int j;
@@ -837,8 +887,8 @@
 	 * have that problem and may take a substantial amount of time to resume
 	 * due to I/O costs and anti-pop so handle them out of line.
 	 */
-	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+	list_for_each_entry(rtd, &card->rtd_list, list) {
+		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 		bus_control |= cpu_dai->driver->bus_control;
 	}
 	if (bus_control) {
@@ -910,18 +960,41 @@
 	return NULL;
 }
 
-static int soc_bind_dai_link(struct snd_soc_card *card, int num)
+static bool soc_is_dai_link_bound(struct snd_soc_card *card,
+		struct snd_soc_dai_link *dai_link)
 {
-	struct snd_soc_dai_link *dai_link = &card->dai_link[num];
-	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+	struct snd_soc_pcm_runtime *rtd;
+
+	list_for_each_entry(rtd, &card->rtd_list, list) {
+		if (rtd->dai_link == dai_link)
+			return true;
+	}
+
+	return false;
+}
+
+static int soc_bind_dai_link(struct snd_soc_card *card,
+	struct snd_soc_dai_link *dai_link)
+{
+	struct snd_soc_pcm_runtime *rtd;
 	struct snd_soc_dai_link_component *codecs = dai_link->codecs;
 	struct snd_soc_dai_link_component cpu_dai_component;
-	struct snd_soc_dai **codec_dais = rtd->codec_dais;
+	struct snd_soc_dai **codec_dais;
 	struct snd_soc_platform *platform;
 	const char *platform_name;
 	int i;
 
-	dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num);
+	dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name);
+
+	rtd = soc_new_pcm_runtime(card, dai_link);
+	if (!rtd)
+		return -ENOMEM;
+
+	if (soc_is_dai_link_bound(card, dai_link)) {
+		dev_dbg(card->dev, "ASoC: dai link %s already bound\n",
+			dai_link->name);
+		return 0;
+	}
 
 	cpu_dai_component.name = dai_link->cpu_name;
 	cpu_dai_component.of_node = dai_link->cpu_of_node;
@@ -930,18 +1003,19 @@
 	if (!rtd->cpu_dai) {
 		dev_err(card->dev, "ASoC: CPU DAI %s not registered\n",
 			dai_link->cpu_dai_name);
-		return -EPROBE_DEFER;
+		goto _err_defer;
 	}
 
 	rtd->num_codecs = dai_link->num_codecs;
 
 	/* Find CODEC from registered CODECs */
+	codec_dais = rtd->codec_dais;
 	for (i = 0; i < rtd->num_codecs; i++) {
 		codec_dais[i] = snd_soc_find_dai(&codecs[i]);
 		if (!codec_dais[i]) {
 			dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
 				codecs[i].dai_name);
-			return -EPROBE_DEFER;
+			goto _err_defer;
 		}
 	}
 
@@ -973,9 +1047,12 @@
 		return -EPROBE_DEFER;
 	}
 
-	card->num_rtd++;
-
+	soc_add_pcm_runtime(card, rtd);
 	return 0;
+
+_err_defer:
+	soc_free_pcm_runtime(rtd);
+	return  -EPROBE_DEFER;
 }
 
 static void soc_remove_component(struct snd_soc_component *component)
@@ -1014,9 +1091,9 @@
 	}
 }
 
-static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
+static void soc_remove_link_dais(struct snd_soc_card *card,
+		struct snd_soc_pcm_runtime *rtd, int order)
 {
-	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
 	int i;
 
 	/* unregister the rtd device */
@@ -1032,10 +1109,9 @@
 	soc_remove_dai(rtd->cpu_dai, order);
 }
 
-static void soc_remove_link_components(struct snd_soc_card *card, int num,
-				       int order)
+static void soc_remove_link_components(struct snd_soc_card *card,
+	struct snd_soc_pcm_runtime *rtd, int order)
 {
-	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
@@ -1061,23 +1137,200 @@
 
 static void soc_remove_dai_links(struct snd_soc_card *card)
 {
-	int dai, order;
+	int order;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai_link *link, *_link;
 
 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
 			order++) {
-		for (dai = 0; dai < card->num_rtd; dai++)
-			soc_remove_link_dais(card, dai, order);
+		list_for_each_entry(rtd, &card->rtd_list, list)
+			soc_remove_link_dais(card, rtd, order);
 	}
 
 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
 			order++) {
-		for (dai = 0; dai < card->num_rtd; dai++)
-			soc_remove_link_components(card, dai, order);
+		list_for_each_entry(rtd, &card->rtd_list, list)
+			soc_remove_link_components(card, rtd, order);
 	}
 
-	card->num_rtd = 0;
+	list_for_each_entry_safe(link, _link, &card->dai_link_list, list) {
+		if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK)
+			dev_warn(card->dev, "Topology forgot to remove link %s?\n",
+				link->name);
+
+		list_del(&link->list);
+		card->num_dai_links--;
+	}
 }
 
+static int snd_soc_init_multicodec(struct snd_soc_card *card,
+				   struct snd_soc_dai_link *dai_link)
+{
+	/* Legacy codec/codec_dai link is a single entry in multicodec */
+	if (dai_link->codec_name || dai_link->codec_of_node ||
+	    dai_link->codec_dai_name) {
+		dai_link->num_codecs = 1;
+
+		dai_link->codecs = devm_kzalloc(card->dev,
+				sizeof(struct snd_soc_dai_link_component),
+				GFP_KERNEL);
+		if (!dai_link->codecs)
+			return -ENOMEM;
+
+		dai_link->codecs[0].name = dai_link->codec_name;
+		dai_link->codecs[0].of_node = dai_link->codec_of_node;
+		dai_link->codecs[0].dai_name = dai_link->codec_dai_name;
+	}
+
+	if (!dai_link->codecs) {
+		dev_err(card->dev, "ASoC: DAI link has no CODECs\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int soc_init_dai_link(struct snd_soc_card *card,
+				   struct snd_soc_dai_link *link)
+{
+	int i, ret;
+
+	ret = snd_soc_init_multicodec(card, link);
+	if (ret) {
+		dev_err(card->dev, "ASoC: failed to init multicodec\n");
+		return ret;
+	}
+
+	for (i = 0; i < link->num_codecs; i++) {
+		/*
+		 * Codec must be specified by 1 of name or OF node,
+		 * not both or neither.
+		 */
+		if (!!link->codecs[i].name ==
+		    !!link->codecs[i].of_node) {
+			dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n",
+				link->name);
+			return -EINVAL;
+		}
+		/* Codec DAI name must be specified */
+		if (!link->codecs[i].dai_name) {
+			dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n",
+				link->name);
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * Platform may be specified by either name or OF node, but
+	 * can be left unspecified, and a dummy platform will be used.
+	 */
+	if (link->platform_name && link->platform_of_node) {
+		dev_err(card->dev,
+			"ASoC: Both platform name/of_node are set for %s\n",
+			link->name);
+		return -EINVAL;
+	}
+
+	/*
+	 * CPU device may be specified by either name or OF node, but
+	 * can be left unspecified, and will be matched based on DAI
+	 * name alone..
+	 */
+	if (link->cpu_name && link->cpu_of_node) {
+		dev_err(card->dev,
+			"ASoC: Neither/both cpu name/of_node are set for %s\n",
+			link->name);
+		return -EINVAL;
+	}
+	/*
+	 * At least one of CPU DAI name or CPU device name/node must be
+	 * specified
+	 */
+	if (!link->cpu_dai_name &&
+	    !(link->cpu_name || link->cpu_of_node)) {
+		dev_err(card->dev,
+			"ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
+			link->name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * snd_soc_add_dai_link - Add a DAI link dynamically
+ * @card: The ASoC card to which the DAI link is added
+ * @dai_link: The new DAI link to add
+ *
+ * This function adds a DAI link to the ASoC card's link list.
+ *
+ * Note: Topology can use this API to add DAI links when probing the
+ * topology component. And machine drivers can still define static
+ * DAI links in dai_link array.
+ */
+int snd_soc_add_dai_link(struct snd_soc_card *card,
+		struct snd_soc_dai_link *dai_link)
+{
+	if (dai_link->dobj.type
+	    && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) {
+		dev_err(card->dev, "Invalid dai link type %d\n",
+			dai_link->dobj.type);
+		return -EINVAL;
+	}
+
+	lockdep_assert_held(&client_mutex);
+	/* Notify the machine driver for extra initialization
+	 * on the link created by topology.
+	 */
+	if (dai_link->dobj.type && card->add_dai_link)
+		card->add_dai_link(card, dai_link);
+
+	list_add_tail(&dai_link->list, &card->dai_link_list);
+	card->num_dai_links++;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_add_dai_link);
+
+/**
+ * snd_soc_remove_dai_link - Remove a DAI link from the list
+ * @card: The ASoC card that owns the link
+ * @dai_link: The DAI link to remove
+ *
+ * This function removes a DAI link from the ASoC card's link list.
+ *
+ * For DAI links previously added by topology, topology should
+ * remove them by using the dobj embedded in the link.
+ */
+void snd_soc_remove_dai_link(struct snd_soc_card *card,
+			     struct snd_soc_dai_link *dai_link)
+{
+	struct snd_soc_dai_link *link, *_link;
+
+	if (dai_link->dobj.type
+	    && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) {
+		dev_err(card->dev, "Invalid dai link type %d\n",
+			dai_link->dobj.type);
+		return;
+	}
+
+	lockdep_assert_held(&client_mutex);
+	/* Notify the machine driver for extra destruction
+	 * on the link created by topology.
+	 */
+	if (dai_link->dobj.type && card->remove_dai_link)
+		card->remove_dai_link(card, dai_link);
+
+	list_for_each_entry_safe(link, _link, &card->dai_link_list, list) {
+		if (link == dai_link) {
+			list_del(&link->list);
+			card->num_dai_links--;
+			return;
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link);
+
 static void soc_set_name_prefix(struct snd_soc_card *card,
 				struct snd_soc_component *component)
 {
@@ -1160,6 +1413,16 @@
 			component->name);
 	}
 
+	/* machine specific init */
+	if (component->init) {
+		ret = component->init(component);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to do machine specific init %d\n", ret);
+			goto err_probe;
+		}
+	}
+
 	if (component->controls)
 		snd_soc_add_component_controls(component, component->controls,
 				     component->num_controls);
@@ -1220,10 +1483,10 @@
 	return 0;
 }
 
-static int soc_probe_link_components(struct snd_soc_card *card, int num,
+static int soc_probe_link_components(struct snd_soc_card *card,
+			struct snd_soc_pcm_runtime *rtd,
 				     int order)
 {
-	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
 	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_component *component;
 	int i, ret;
@@ -1283,35 +1546,35 @@
 {
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_dapm_widget *play_w, *capture_w;
+	struct snd_soc_dapm_widget *sink, *source;
 	int ret;
 
 	if (rtd->num_codecs > 1)
 		dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n");
 
 	/* link the DAI widgets */
-	play_w = codec_dai->playback_widget;
-	capture_w = cpu_dai->capture_widget;
-	if (play_w && capture_w) {
+	sink = codec_dai->playback_widget;
+	source = cpu_dai->capture_widget;
+	if (sink && source) {
 		ret = snd_soc_dapm_new_pcm(card, dai_link->params,
-					   dai_link->num_params, capture_w,
-					   play_w);
+					   dai_link->num_params,
+					   source, sink);
 		if (ret != 0) {
 			dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
-				play_w->name, capture_w->name, ret);
+				sink->name, source->name, ret);
 			return ret;
 		}
 	}
 
-	play_w = cpu_dai->playback_widget;
-	capture_w = codec_dai->capture_widget;
-	if (play_w && capture_w) {
+	sink = cpu_dai->playback_widget;
+	source = codec_dai->capture_widget;
+	if (sink && source) {
 		ret = snd_soc_dapm_new_pcm(card, dai_link->params,
-					   dai_link->num_params, capture_w,
-					   play_w);
+					   dai_link->num_params,
+					   source, sink);
 		if (ret != 0) {
 			dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
-				play_w->name, capture_w->name, ret);
+				sink->name, source->name, ret);
 			return ret;
 		}
 	}
@@ -1319,15 +1582,15 @@
 	return 0;
 }
 
-static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
+static int soc_probe_link_dais(struct snd_soc_card *card,
+		struct snd_soc_pcm_runtime *rtd, int order)
 {
-	struct snd_soc_dai_link *dai_link = &card->dai_link[num];
-	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+	struct snd_soc_dai_link *dai_link = rtd->dai_link;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	int i, ret;
 
 	dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n",
-			card->name, num, order);
+			card->name, rtd->num, order);
 
 	/* set default power off timeout */
 	rtd->pmdown_time = pmdown_time;
@@ -1372,7 +1635,7 @@
 
 	if (cpu_dai->driver->compress_new) {
 		/*create compress_device"*/
-		ret = cpu_dai->driver->compress_new(rtd, num);
+		ret = cpu_dai->driver->compress_new(rtd, rtd->num);
 		if (ret < 0) {
 			dev_err(card->dev, "ASoC: can't create compress %s\n",
 					 dai_link->stream_name);
@@ -1382,7 +1645,7 @@
 
 		if (!dai_link->params) {
 			/* create the pcm */
-			ret = soc_new_pcm(rtd, num);
+			ret = soc_new_pcm(rtd, rtd->num);
 			if (ret < 0) {
 				dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
 				       dai_link->stream_name, ret);
@@ -1404,65 +1667,81 @@
 
 static int soc_bind_aux_dev(struct snd_soc_card *card, int num)
 {
-	struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
 	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
-	const char *name = aux_dev->codec_name;
+	struct snd_soc_component *component;
+	const char *name;
+	struct device_node *codec_of_node;
 
-	rtd->component = soc_find_component(aux_dev->codec_of_node, name);
-	if (!rtd->component) {
-		if (aux_dev->codec_of_node)
-			name = of_node_full_name(aux_dev->codec_of_node);
-
-		dev_err(card->dev, "ASoC: %s not registered\n", name);
-		return -EPROBE_DEFER;
+	if (aux_dev->codec_of_node || aux_dev->codec_name) {
+		/* codecs, usually analog devices */
+		name = aux_dev->codec_name;
+		codec_of_node = aux_dev->codec_of_node;
+		component = soc_find_component(codec_of_node, name);
+		if (!component) {
+			if (codec_of_node)
+				name = of_node_full_name(codec_of_node);
+			goto err_defer;
+		}
+	} else if (aux_dev->name) {
+		/* generic components */
+		name = aux_dev->name;
+		component = soc_find_component(NULL, name);
+		if (!component)
+			goto err_defer;
+	} else {
+		dev_err(card->dev, "ASoC: Invalid auxiliary device\n");
+		return -EINVAL;
 	}
 
-	/*
-	 * Some places still reference rtd->codec, so we have to keep that
-	 * initialized if the component is a CODEC. Once all those references
-	 * have been removed, this code can be removed as well.
-	 */
-	 rtd->codec = rtd->component->codec;
+	component->init = aux_dev->init;
+	list_add(&component->list_aux, &card->aux_comp_list);
+	return 0;
+
+err_defer:
+	dev_err(card->dev, "ASoC: %s not registered\n", name);
+	return -EPROBE_DEFER;
+}
+
+static int soc_probe_aux_devices(struct snd_soc_card *card)
+{
+	struct snd_soc_component *comp;
+	int order;
+	int ret;
+
+	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
+		order++) {
+		list_for_each_entry(comp, &card->aux_comp_list, list_aux) {
+			if (comp->driver->probe_order == order) {
+				ret = soc_probe_component(card,	comp);
+				if (ret < 0) {
+					dev_err(card->dev,
+						"ASoC: failed to probe aux component %s %d\n",
+						comp->name, ret);
+					return ret;
+				}
+			}
+		}
+	}
 
 	return 0;
 }
 
-static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
+static void soc_remove_aux_devices(struct snd_soc_card *card)
 {
-	struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
-	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
-	int ret;
+	struct snd_soc_component *comp, *_comp;
+	int order;
 
-	ret = soc_probe_component(card, rtd->component);
-	if (ret < 0)
-		return ret;
-
-	/* do machine specific initialization */
-	if (aux_dev->init) {
-		ret = aux_dev->init(rtd->component);
-		if (ret < 0) {
-			dev_err(card->dev, "ASoC: failed to init %s: %d\n",
-				aux_dev->name, ret);
-			return ret;
+	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
+		order++) {
+		list_for_each_entry_safe(comp, _comp,
+			&card->aux_comp_list, list_aux) {
+			if (comp->driver->remove_order == order) {
+				soc_remove_component(comp);
+				/* remove it from the card's aux_comp_list */
+				list_del(&comp->list_aux);
+			}
 		}
 	}
-
-	return soc_post_component_init(rtd, aux_dev->name);
-}
-
-static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
-{
-	struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
-	struct snd_soc_component *component = rtd->component;
-
-	/* unregister the rtd device */
-	if (rtd->dev_registered) {
-		device_unregister(rtd->dev);
-		rtd->dev_registered = 0;
-	}
-
-	if (component)
-		soc_remove_component(component);
 }
 
 static int snd_soc_init_codec_cache(struct snd_soc_codec *codec)
@@ -1552,6 +1831,8 @@
 static int snd_soc_instantiate_card(struct snd_soc_card *card)
 {
 	struct snd_soc_codec *codec;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai_link *dai_link;
 	int ret, i, order;
 
 	mutex_lock(&client_mutex);
@@ -1559,7 +1840,7 @@
 
 	/* bind DAIs */
 	for (i = 0; i < card->num_links; i++) {
-		ret = soc_bind_dai_link(card, i);
+		ret = soc_bind_dai_link(card, &card->dai_link[i]);
 		if (ret != 0)
 			goto base_error;
 	}
@@ -1571,6 +1852,10 @@
 			goto base_error;
 	}
 
+	/* add predefined DAI links to the list */
+	for (i = 0; i < card->num_links; i++)
+		snd_soc_add_dai_link(card, card->dai_link+i);
+
 	/* initialize the register cache for each available codec */
 	list_for_each_entry(codec, &codec_list, list) {
 		if (codec->cache_init)
@@ -1624,8 +1909,8 @@
 	/* probe all components used by DAI links on this card */
 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
 			order++) {
-		for (i = 0; i < card->num_links; i++) {
-			ret = soc_probe_link_components(card, i, order);
+		list_for_each_entry(rtd, &card->rtd_list, list) {
+			ret = soc_probe_link_components(card, rtd, order);
 			if (ret < 0) {
 				dev_err(card->dev,
 					"ASoC: failed to instantiate card %d\n",
@@ -1635,11 +1920,31 @@
 		}
 	}
 
+	/* probe auxiliary components */
+	ret = soc_probe_aux_devices(card);
+	if (ret < 0)
+		goto probe_dai_err;
+
+	/* Find new DAI links added during probing components and bind them.
+	 * Components with topology may bring new DAIs and DAI links.
+	 */
+	list_for_each_entry(dai_link, &card->dai_link_list, list) {
+		if (soc_is_dai_link_bound(card, dai_link))
+			continue;
+
+		ret = soc_init_dai_link(card, dai_link);
+		if (ret)
+			goto probe_dai_err;
+		ret = soc_bind_dai_link(card, dai_link);
+		if (ret)
+			goto probe_dai_err;
+	}
+
 	/* probe all DAI links on this card */
 	for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
 			order++) {
-		for (i = 0; i < card->num_links; i++) {
-			ret = soc_probe_link_dais(card, i, order);
+		list_for_each_entry(rtd, &card->rtd_list, list) {
+			ret = soc_probe_link_dais(card, rtd, order);
 			if (ret < 0) {
 				dev_err(card->dev,
 					"ASoC: failed to instantiate card %d\n",
@@ -1649,16 +1954,6 @@
 		}
 	}
 
-	for (i = 0; i < card->num_aux_devs; i++) {
-		ret = soc_probe_aux_dev(card, i);
-		if (ret < 0) {
-			dev_err(card->dev,
-				"ASoC: failed to add auxiliary devices %d\n",
-				ret);
-			goto probe_aux_dev_err;
-		}
-	}
-
 	snd_soc_dapm_link_dai_widgets(card);
 	snd_soc_dapm_connect_dai_link_widgets(card);
 
@@ -1718,8 +2013,7 @@
 	return 0;
 
 probe_aux_dev_err:
-	for (i = 0; i < card->num_aux_devs; i++)
-		soc_remove_aux_dev(card, i);
+	soc_remove_aux_devices(card);
 
 probe_dai_err:
 	soc_remove_dai_links(card);
@@ -1733,6 +2027,7 @@
 	snd_card_free(card->snd_card);
 
 base_error:
+	soc_remove_pcm_runtimes(card);
 	mutex_unlock(&card->mutex);
 	mutex_unlock(&client_mutex);
 
@@ -1763,20 +2058,18 @@
 
 static int soc_cleanup_card_resources(struct snd_soc_card *card)
 {
-	int i;
+	struct snd_soc_pcm_runtime *rtd;
 
 	/* make sure any delayed work runs */
-	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+	list_for_each_entry(rtd, &card->rtd_list, list)
 		flush_delayed_work(&rtd->delayed_work);
-	}
-
-	/* remove auxiliary devices */
-	for (i = 0; i < card->num_aux_devs; i++)
-		soc_remove_aux_dev(card, i);
 
 	/* remove and free each DAI */
 	soc_remove_dai_links(card);
+	soc_remove_pcm_runtimes(card);
+
+	/* remove auxiliary devices */
+	soc_remove_aux_devices(card);
 
 	soc_cleanup_card_debugfs(card);
 
@@ -1803,29 +2096,26 @@
 int snd_soc_poweroff(struct device *dev)
 {
 	struct snd_soc_card *card = dev_get_drvdata(dev);
-	int i;
+	struct snd_soc_pcm_runtime *rtd;
 
 	if (!card->instantiated)
 		return 0;
 
 	/* Flush out pmdown_time work - we actually do want to run it
 	 * now, we're shutting down so no imminent restart. */
-	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+	list_for_each_entry(rtd, &card->rtd_list, list)
 		flush_delayed_work(&rtd->delayed_work);
-	}
 
 	snd_soc_dapm_shutdown(card);
 
 	/* deactivate pins to sleep state */
-	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+	list_for_each_entry(rtd, &card->rtd_list, list) {
 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-		int j;
+		int i;
 
 		pinctrl_pm_select_sleep_state(cpu_dai->dev);
-		for (j = 0; j < rtd->num_codecs; j++) {
-			struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
+		for (i = 0; i < rtd->num_codecs; i++) {
+			struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
 			pinctrl_pm_select_sleep_state(codec_dai->dev);
 		}
 	}
@@ -2301,33 +2591,6 @@
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
 
-static int snd_soc_init_multicodec(struct snd_soc_card *card,
-				   struct snd_soc_dai_link *dai_link)
-{
-	/* Legacy codec/codec_dai link is a single entry in multicodec */
-	if (dai_link->codec_name || dai_link->codec_of_node ||
-	    dai_link->codec_dai_name) {
-		dai_link->num_codecs = 1;
-
-		dai_link->codecs = devm_kzalloc(card->dev,
-				sizeof(struct snd_soc_dai_link_component),
-				GFP_KERNEL);
-		if (!dai_link->codecs)
-			return -ENOMEM;
-
-		dai_link->codecs[0].name = dai_link->codec_name;
-		dai_link->codecs[0].of_node = dai_link->codec_of_node;
-		dai_link->codecs[0].dai_name = dai_link->codec_dai_name;
-	}
-
-	if (!dai_link->codecs) {
-		dev_err(card->dev, "ASoC: DAI link has no CODECs\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 /**
  * snd_soc_register_card - Register a card with the ASoC core
  *
@@ -2336,7 +2599,8 @@
  */
 int snd_soc_register_card(struct snd_soc_card *card)
 {
-	int i, j, ret;
+	int i, ret;
+	struct snd_soc_pcm_runtime *rtd;
 
 	if (!card->name || !card->dev)
 		return -EINVAL;
@@ -2344,92 +2608,23 @@
 	for (i = 0; i < card->num_links; i++) {
 		struct snd_soc_dai_link *link = &card->dai_link[i];
 
-		ret = snd_soc_init_multicodec(card, link);
+		ret = soc_init_dai_link(card, link);
 		if (ret) {
-			dev_err(card->dev, "ASoC: failed to init multicodec\n");
+			dev_err(card->dev, "ASoC: failed to init link %s\n",
+				link->name);
 			return ret;
 		}
-
-		for (j = 0; j < link->num_codecs; j++) {
-			/*
-			 * Codec must be specified by 1 of name or OF node,
-			 * not both or neither.
-			 */
-			if (!!link->codecs[j].name ==
-			    !!link->codecs[j].of_node) {
-				dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n",
-					link->name);
-				return -EINVAL;
-			}
-			/* Codec DAI name must be specified */
-			if (!link->codecs[j].dai_name) {
-				dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n",
-					link->name);
-				return -EINVAL;
-			}
-		}
-
-		/*
-		 * Platform may be specified by either name or OF node, but
-		 * can be left unspecified, and a dummy platform will be used.
-		 */
-		if (link->platform_name && link->platform_of_node) {
-			dev_err(card->dev,
-				"ASoC: Both platform name/of_node are set for %s\n",
-				link->name);
-			return -EINVAL;
-		}
-
-		/*
-		 * CPU device may be specified by either name or OF node, but
-		 * can be left unspecified, and will be matched based on DAI
-		 * name alone..
-		 */
-		if (link->cpu_name && link->cpu_of_node) {
-			dev_err(card->dev,
-				"ASoC: Neither/both cpu name/of_node are set for %s\n",
-				link->name);
-			return -EINVAL;
-		}
-		/*
-		 * At least one of CPU DAI name or CPU device name/node must be
-		 * specified
-		 */
-		if (!link->cpu_dai_name &&
-		    !(link->cpu_name || link->cpu_of_node)) {
-			dev_err(card->dev,
-				"ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
-				link->name);
-			return -EINVAL;
-		}
 	}
 
 	dev_set_drvdata(card->dev, card);
 
 	snd_soc_initialize_card_lists(card);
 
-	card->rtd = devm_kzalloc(card->dev,
-				 sizeof(struct snd_soc_pcm_runtime) *
-				 (card->num_links + card->num_aux_devs),
-				 GFP_KERNEL);
-	if (card->rtd == NULL)
-		return -ENOMEM;
+	INIT_LIST_HEAD(&card->dai_link_list);
+	card->num_dai_links = 0;
+
+	INIT_LIST_HEAD(&card->rtd_list);
 	card->num_rtd = 0;
-	card->rtd_aux = &card->rtd[card->num_links];
-
-	for (i = 0; i < card->num_links; i++) {
-		card->rtd[i].card = card;
-		card->rtd[i].dai_link = &card->dai_link[i];
-		card->rtd[i].codec_dais = devm_kzalloc(card->dev,
-					sizeof(struct snd_soc_dai *) *
-					(card->rtd[i].dai_link->num_codecs),
-					GFP_KERNEL);
-		if (card->rtd[i].codec_dais == NULL)
-			return -ENOMEM;
-	}
-
-	for (i = 0; i < card->num_aux_devs; i++)
-		card->rtd_aux[i].card = card;
 
 	INIT_LIST_HEAD(&card->dapm_dirty);
 	INIT_LIST_HEAD(&card->dobj_list);
@@ -2442,8 +2637,7 @@
 		return ret;
 
 	/* deactivate pins to sleep state */
-	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+	list_for_each_entry(rtd, &card->rtd_list, list)  {
 		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 		int j;
 
@@ -2558,6 +2752,56 @@
 	}
 }
 
+/* Create a DAI and add it to the component's DAI list */
+static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component,
+	struct snd_soc_dai_driver *dai_drv,
+	bool legacy_dai_naming)
+{
+	struct device *dev = component->dev;
+	struct snd_soc_dai *dai;
+
+	dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev));
+
+	dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
+	if (dai == NULL)
+		return NULL;
+
+	/*
+	 * Back in the old days when we still had component-less DAIs,
+	 * instead of having a static name, component-less DAIs would
+	 * inherit the name of the parent device so it is possible to
+	 * register multiple instances of the DAI. We still need to keep
+	 * the same naming style even though those DAIs are not
+	 * component-less anymore.
+	 */
+	if (legacy_dai_naming &&
+	   (dai_drv->id == 0 || dai_drv->name == NULL)) {
+		dai->name = fmt_single_name(dev, &dai->id);
+	} else {
+		dai->name = fmt_multiple_name(dev, dai_drv);
+		if (dai_drv->id)
+			dai->id = dai_drv->id;
+		else
+			dai->id = component->num_dai;
+	}
+	if (dai->name == NULL) {
+		kfree(dai);
+		return NULL;
+	}
+
+	dai->component = component;
+	dai->dev = dev;
+	dai->driver = dai_drv;
+	if (!dai->driver->ops)
+		dai->driver->ops = &null_dai_ops;
+
+	list_add(&dai->list, &component->dai_list);
+	component->num_dai++;
+
+	dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
+	return dai;
+}
+
 /**
  * snd_soc_register_dais - Register a DAI with the ASoC core
  *
@@ -2579,49 +2823,15 @@
 	dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);
 
 	component->dai_drv = dai_drv;
-	component->num_dai = count;
 
 	for (i = 0; i < count; i++) {
 
-		dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
+		dai = soc_add_dai(component, dai_drv + i,
+				count == 1 && legacy_dai_naming);
 		if (dai == NULL) {
 			ret = -ENOMEM;
 			goto err;
 		}
-
-		/*
-		 * Back in the old days when we still had component-less DAIs,
-		 * instead of having a static name, component-less DAIs would
-		 * inherit the name of the parent device so it is possible to
-		 * register multiple instances of the DAI. We still need to keep
-		 * the same naming style even though those DAIs are not
-		 * component-less anymore.
-		 */
-		if (count == 1 && legacy_dai_naming &&
-			(dai_drv[i].id == 0 || dai_drv[i].name == NULL)) {
-			dai->name = fmt_single_name(dev, &dai->id);
-		} else {
-			dai->name = fmt_multiple_name(dev, &dai_drv[i]);
-			if (dai_drv[i].id)
-				dai->id = dai_drv[i].id;
-			else
-				dai->id = i;
-		}
-		if (dai->name == NULL) {
-			kfree(dai);
-			ret = -ENOMEM;
-			goto err;
-		}
-
-		dai->component = component;
-		dai->dev = dev;
-		dai->driver = &dai_drv[i];
-		if (!dai->driver->ops)
-			dai->driver->ops = &null_dai_ops;
-
-		list_add(&dai->list, &component->dai_list);
-
-		dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
 	}
 
 	return 0;
@@ -2632,6 +2842,48 @@
 	return ret;
 }
 
+/**
+ * snd_soc_register_dai - Register a DAI dynamically & create its widgets
+ *
+ * @component: The component the DAIs are registered for
+ * @dai_drv: DAI driver to use for the DAI
+ *
+ * Topology can use this API to register DAIs when probing a component.
+ * These DAIs's widgets will be freed in the card cleanup and the DAIs
+ * will be freed in the component cleanup.
+ */
+int snd_soc_register_dai(struct snd_soc_component *component,
+	struct snd_soc_dai_driver *dai_drv)
+{
+	struct snd_soc_dapm_context *dapm =
+		snd_soc_component_get_dapm(component);
+	struct snd_soc_dai *dai;
+	int ret;
+
+	if (dai_drv->dobj.type != SND_SOC_DOBJ_PCM) {
+		dev_err(component->dev, "Invalid dai type %d\n",
+			dai_drv->dobj.type);
+		return -EINVAL;
+	}
+
+	lockdep_assert_held(&client_mutex);
+	dai = soc_add_dai(component, dai_drv, false);
+	if (!dai)
+		return -ENOMEM;
+
+	/* Create the DAI widgets here. After adding DAIs, topology may
+	 * also add routes that need these widgets as source or sink.
+	 */
+	ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
+	if (ret != 0) {
+		dev_err(component->dev,
+			"Failed to create DAI widgets %d\n", ret);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_register_dai);
+
 static void snd_soc_component_seq_notifier(struct snd_soc_dapm_context *dapm,
 	enum snd_soc_dapm_type type, int subseq)
 {
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 7d00942..5a2812f 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1300,7 +1300,7 @@
 
 static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
 {
-	return 1;
+	return w->connected;
 }
 
 static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
@@ -3358,6 +3358,11 @@
 		w->is_ep = SND_SOC_DAPM_EP_SOURCE;
 		w->power_check = dapm_always_on_check_power;
 		break;
+	case snd_soc_dapm_sink:
+		w->is_ep = SND_SOC_DAPM_EP_SINK;
+		w->power_check = dapm_always_on_check_power;
+		break;
+
 	case snd_soc_dapm_mux:
 	case snd_soc_dapm_demux:
 	case snd_soc_dapm_switch:
@@ -3900,13 +3905,10 @@
 
 void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
 {
-	struct snd_soc_pcm_runtime *rtd = card->rtd;
-	int i;
+	struct snd_soc_pcm_runtime *rtd;
 
 	/* for each BE DAI link... */
-	for (i = 0; i < card->num_rtd; i++) {
-		rtd = &card->rtd[i];
-
+	list_for_each_entry(rtd, &card->rtd_list, list)  {
 		/*
 		 * dynamic FE links have no fixed DAI mapping.
 		 * CODEC<->CODEC links have no direct connection.
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index 2f67ba6..a513a34 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -779,11 +779,11 @@
 	switch (op_flag) {
 	case SNDRV_CTL_TLV_OP_READ:
 		if (params->get)
-			ret = params->get(tlv, count);
+			ret = params->get(kcontrol, tlv, count);
 		break;
 	case SNDRV_CTL_TLV_OP_WRITE:
 		if (params->put)
-			ret = params->put(tlv, count);
+			ret = params->put(kcontrol, tlv, count);
 		break;
 	}
 	return ret;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index c86dc96..e898b42 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -599,10 +599,15 @@
 out:
 	mutex_unlock(&rtd->pcm_mutex);
 
-	pm_runtime_put(platform->dev);
-	for (i = 0; i < rtd->num_codecs; i++)
-		pm_runtime_put(rtd->codec_dais[i]->dev);
-	pm_runtime_put(cpu_dai->dev);
+	pm_runtime_mark_last_busy(platform->dev);
+	pm_runtime_put_autosuspend(platform->dev);
+	for (i = 0; i < rtd->num_codecs; i++) {
+		pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev);
+		pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev);
+	}
+
+	pm_runtime_mark_last_busy(cpu_dai->dev);
+	pm_runtime_put_autosuspend(cpu_dai->dev);
 	for (i = 0; i < rtd->num_codecs; i++) {
 		if (!rtd->codec_dais[i]->active)
 			pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
@@ -706,10 +711,17 @@
 
 	mutex_unlock(&rtd->pcm_mutex);
 
-	pm_runtime_put(platform->dev);
-	for (i = 0; i < rtd->num_codecs; i++)
-		pm_runtime_put(rtd->codec_dais[i]->dev);
-	pm_runtime_put(cpu_dai->dev);
+	pm_runtime_mark_last_busy(platform->dev);
+	pm_runtime_put_autosuspend(platform->dev);
+
+	for (i = 0; i < rtd->num_codecs; i++) {
+		pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev);
+		pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev);
+	}
+
+	pm_runtime_mark_last_busy(cpu_dai->dev);
+	pm_runtime_put_autosuspend(cpu_dai->dev);
+
 	for (i = 0; i < rtd->num_codecs; i++) {
 		if (!rtd->codec_dais[i]->active)
 			pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
@@ -1213,11 +1225,10 @@
 		struct snd_soc_dapm_widget *widget, int stream)
 {
 	struct snd_soc_pcm_runtime *be;
-	int i, j;
+	int i;
 
 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		for (i = 0; i < card->num_links; i++) {
-			be = &card->rtd[i];
+		list_for_each_entry(be, &card->rtd_list, list) {
 
 			if (!be->dai_link->no_pcm)
 				continue;
@@ -1225,16 +1236,15 @@
 			if (be->cpu_dai->playback_widget == widget)
 				return be;
 
-			for (j = 0; j < be->num_codecs; j++) {
-				struct snd_soc_dai *dai = be->codec_dais[j];
+			for (i = 0; i < be->num_codecs; i++) {
+				struct snd_soc_dai *dai = be->codec_dais[i];
 				if (dai->playback_widget == widget)
 					return be;
 			}
 		}
 	} else {
 
-		for (i = 0; i < card->num_links; i++) {
-			be = &card->rtd[i];
+		list_for_each_entry(be, &card->rtd_list, list) {
 
 			if (!be->dai_link->no_pcm)
 				continue;
@@ -1242,8 +1252,8 @@
 			if (be->cpu_dai->capture_widget == widget)
 				return be;
 
-			for (j = 0; j < be->num_codecs; j++) {
-				struct snd_soc_dai *dai = be->codec_dais[j];
+			for (i = 0; i < be->num_codecs; i++) {
+				struct snd_soc_dai *dai = be->codec_dais[i];
 				if (dai->capture_widget == widget)
 					return be;
 			}
@@ -1616,6 +1626,56 @@
 	snd_pcm_stream_unlock_irq(substream);
 }
 
+static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
+			       int stream)
+{
+	struct snd_soc_dpcm *dpcm;
+	struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
+	struct snd_soc_dai *fe_cpu_dai = fe->cpu_dai;
+	int err;
+
+	/* apply symmetry for FE */
+	if (soc_pcm_has_symmetry(fe_substream))
+		fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
+
+	/* Symmetry only applies if we've got an active stream. */
+	if (fe_cpu_dai->active) {
+		err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
+		if (err < 0)
+			return err;
+	}
+
+	/* apply symmetry for BE */
+	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+		struct snd_soc_pcm_runtime *be = dpcm->be;
+		struct snd_pcm_substream *be_substream =
+			snd_soc_dpcm_get_substream(be, stream);
+		struct snd_soc_pcm_runtime *rtd = be_substream->private_data;
+		int i;
+
+		if (soc_pcm_has_symmetry(be_substream))
+			be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
+
+		/* Symmetry only applies if we've got an active stream. */
+		if (rtd->cpu_dai->active) {
+			err = soc_pcm_apply_symmetry(be_substream, rtd->cpu_dai);
+			if (err < 0)
+				return err;
+		}
+
+		for (i = 0; i < rtd->num_codecs; i++) {
+			if (rtd->codec_dais[i]->active) {
+				err = soc_pcm_apply_symmetry(be_substream,
+							     rtd->codec_dais[i]);
+				if (err < 0)
+					return err;
+			}
+		}
+	}
+
+	return 0;
+}
+
 static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
 {
 	struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
@@ -1644,6 +1704,13 @@
 	dpcm_set_fe_runtime(fe_substream);
 	snd_pcm_limit_hw_rates(runtime);
 
+	ret = dpcm_apply_symmetry(fe_substream, stream);
+	if (ret < 0) {
+		dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
+			ret);
+		goto unwind;
+	}
+
 	dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
 	return 0;
 
@@ -2115,7 +2182,8 @@
 			continue;
 
 		if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
-		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
+		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
 			continue;
 
 		dev_dbg(be->dev, "ASoC: prepare BE %s\n",
@@ -2343,12 +2411,12 @@
  */
 int soc_dpcm_runtime_update(struct snd_soc_card *card)
 {
-	int i, old, new, paths;
+	struct snd_soc_pcm_runtime *fe;
+	int old, new, paths;
 
 	mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
-	for (i = 0; i < card->num_rtd; i++) {
+	list_for_each_entry(fe, &card->rtd_list, list) {
 		struct snd_soc_dapm_widget_list *list;
-		struct snd_soc_pcm_runtime *fe = &card->rtd[i];
 
 		/* make sure link is FE */
 		if (!fe->dai_link->dynamic)
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c
index 5c2bc53..7aca6b9 100644
--- a/sound/soc/sti/uniperif_player.c
+++ b/sound/soc/sti/uniperif_player.c
@@ -251,8 +251,7 @@
 	 * set one.
 	 */
 	mutex_lock(&player->ctrl_lock);
-	if (runtime && (player->stream_settings.iec958.status[3]
-					== IEC958_AES3_CON_FS_NOTID)) {
+	if (runtime) {
 		switch (runtime->rate) {
 		case 22050:
 			player->stream_settings.iec958.status[3] =
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 1bb896d..44f170c 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -28,6 +28,7 @@
 #include <linux/of_address.h>
 #include <linux/clk.h>
 #include <linux/regmap.h>
+#include <linux/gpio/consumer.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -70,6 +71,7 @@
 
 /* Codec ADC register offsets and bit fields */
 #define SUN4I_CODEC_ADC_FIFOC			(0x1c)
+#define SUN4I_CODEC_ADC_FIFOC_ADC_FS			(29)
 #define SUN4I_CODEC_ADC_FIFOC_EN_AD			(28)
 #define SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE		(24)
 #define SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL		(8)
@@ -102,17 +104,14 @@
 	struct regmap	*regmap;
 	struct clk	*clk_apb;
 	struct clk	*clk_module;
+	struct gpio_desc *gpio_pa;
 
+	struct snd_dmaengine_dai_dma_data	capture_dma_data;
 	struct snd_dmaengine_dai_dma_data	playback_dma_data;
 };
 
 static void sun4i_codec_start_playback(struct sun4i_codec *scodec)
 {
-	/*
-	 * FIXME: according to the BSP, we might need to drive a PA
-	 *        GPIO high here on some boards
-	 */
-
 	/* Flush TX FIFO */
 	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 			   BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
@@ -126,37 +125,50 @@
 
 static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
 {
-	/*
-	 * FIXME: according to the BSP, we might need to drive a PA
-	 *        GPIO low here on some boards
-	 */
-
 	/* Disable DAC DRQ */
 	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 			   BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
 			   0);
 }
 
+static void sun4i_codec_start_capture(struct sun4i_codec *scodec)
+{
+	/* Enable ADC DRQ */
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+			   BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN),
+			   BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
+}
+
+static void sun4i_codec_stop_capture(struct sun4i_codec *scodec)
+{
+	/* Disable ADC DRQ */
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+			   BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0);
+}
+
 static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
 			       struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
 
-	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
-		return -ENOTSUPP;
-
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		sun4i_codec_start_playback(scodec);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			sun4i_codec_start_playback(scodec);
+		else
+			sun4i_codec_start_capture(scodec);
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		sun4i_codec_stop_playback(scodec);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			sun4i_codec_stop_playback(scodec);
+		else
+			sun4i_codec_stop_capture(scodec);
 		break;
 
 	default:
@@ -166,16 +178,55 @@
 	return 0;
 }
 
-static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
-			       struct snd_soc_dai *dai)
+static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
+				       struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+
+
+	/* Flush RX FIFO */
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+			   BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH),
+			   BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH));
+
+
+	/* Set RX FIFO trigger level */
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+			   0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
+			   0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL);
+
+	/*
+	 * FIXME: Undocumented in the datasheet, but
+	 *        Allwinner's code mentions that it is related
+	 *        related to microphone gain
+	 */
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL,
+			   0x3 << 25,
+			   0x1 << 25);
+
+	if (of_device_is_compatible(scodec->dev->of_node,
+				    "allwinner,sun7i-a20-codec"))
+		/* FIXME: Undocumented bits */
+		regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_TUNE,
+				   0x3 << 8,
+				   0x1 << 8);
+
+	/* Fill most significant bits with valid data MSB */
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+			   BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
+			   BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
+
+	return 0;
+}
+
+static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
 	u32 val;
 
-	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
-		return -ENOTSUPP;
-
 	/* Flush the TX FIFO */
 	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 			   BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
@@ -203,6 +254,15 @@
 			   0);
 
 	return 0;
+};
+
+static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return sun4i_codec_prepare_playback(substream, dai);
+
+	return sun4i_codec_prepare_capture(substream, dai);
 }
 
 static unsigned long sun4i_codec_get_mod_freq(struct snd_pcm_hw_params *params)
@@ -277,31 +337,33 @@
 	}
 }
 
-static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
-				 struct snd_pcm_hw_params *params,
-				 struct snd_soc_dai *dai)
+static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec,
+					 struct snd_pcm_hw_params *params,
+					 unsigned int hwrate)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
-	unsigned long clk_freq;
-	int ret, hwrate;
+	/* Set ADC sample rate */
+	regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+			   7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS,
+			   hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS);
+
+	/* Set the number of channels we want to use */
+	if (params_channels(params) == 1)
+		regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+				   BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
+				   BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
+	else
+		regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
+				   BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), 0);
+
+	return 0;
+}
+
+static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec,
+					  struct snd_pcm_hw_params *params,
+					  unsigned int hwrate)
+{
 	u32 val;
 
-	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
-		return -ENOTSUPP;
-
-	clk_freq = sun4i_codec_get_mod_freq(params);
-	if (!clk_freq)
-		return -EINVAL;
-
-	ret = clk_set_rate(scodec->clk_module, clk_freq);
-	if (ret)
-		return ret;
-
-	hwrate = sun4i_codec_get_hw_rate(params);
-	if (hwrate < 0)
-		return hwrate;
-
 	/* Set DAC sample rate */
 	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
 			   7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS,
@@ -345,6 +407,35 @@
 	return 0;
 }
 
+static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
+	unsigned long clk_freq;
+	int ret, hwrate;
+
+	clk_freq = sun4i_codec_get_mod_freq(params);
+	if (!clk_freq)
+		return -EINVAL;
+
+	ret = clk_set_rate(scodec->clk_module, clk_freq);
+	if (ret)
+		return ret;
+
+	hwrate = sun4i_codec_get_hw_rate(params);
+	if (hwrate < 0)
+		return hwrate;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return sun4i_codec_hw_params_playback(scodec, params,
+						      hwrate);
+
+	return sun4i_codec_hw_params_capture(scodec, params,
+					     hwrate);
+}
+
 static int sun4i_codec_startup(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
@@ -395,6 +486,20 @@
 				  SNDRV_PCM_FMTBIT_S32_LE,
 		.sig_bits	= 24,
 	},
+	.capture = {
+		.stream_name	= "Codec Capture",
+		.channels_min	= 1,
+		.channels_max	= 2,
+		.rate_min	= 8000,
+		.rate_max	= 192000,
+		.rates		= SNDRV_PCM_RATE_8000_48000 |
+				  SNDRV_PCM_RATE_96000 |
+				  SNDRV_PCM_RATE_192000 |
+				  SNDRV_PCM_RATE_KNOT,
+		.formats	= SNDRV_PCM_FMTBIT_S16_LE |
+				  SNDRV_PCM_FMTBIT_S32_LE,
+		.sig_bits	= 24,
+	},
 };
 
 /*** Codec ***/
@@ -429,12 +534,23 @@
 			SUN4I_CODEC_DAC_ACTL_MIXPAS, 1, 0),
 };
 
-static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = {
+	/* Digital parts of the ADCs */
+	SND_SOC_DAPM_SUPPLY("ADC", SUN4I_CODEC_ADC_FIFOC,
+			    SUN4I_CODEC_ADC_FIFOC_EN_AD, 0,
+			    NULL, 0),
+
 	/* Digital parts of the DACs */
 	SND_SOC_DAPM_SUPPLY("DAC", SUN4I_CODEC_DAC_DPC,
 			    SUN4I_CODEC_DAC_DPC_EN_DA, 0,
 			    NULL, 0),
 
+	/* Analog parts of the ADCs */
+	SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
+			 SUN4I_CODEC_ADC_ACTL_ADC_L_EN, 0),
+	SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL,
+			 SUN4I_CODEC_ADC_ACTL_ADC_R_EN, 0),
+
 	/* Analog parts of the DACs */
 	SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
 			 SUN4I_CODEC_DAC_ACTL_DACAENL, 0),
@@ -453,6 +569,14 @@
 	SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL,
 			    SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0),
 
+	/* VMIC */
+	SND_SOC_DAPM_SUPPLY("VMIC", SUN4I_CODEC_ADC_ACTL,
+			    SUN4I_CODEC_ADC_ACTL_VMICEN, 0, NULL, 0),
+
+	/* Mic Pre-Amplifiers */
+	SND_SOC_DAPM_PGA("MIC1 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
+			 SUN4I_CODEC_ADC_ACTL_PREG1EN, 0, NULL, 0),
+
 	/* Power Amplifier */
 	SND_SOC_DAPM_MIXER("Power Amplifier", SUN4I_CODEC_ADC_ACTL,
 			   SUN4I_CODEC_ADC_ACTL_PA_EN, 0,
@@ -461,15 +585,19 @@
 	SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0,
 			    &sun4i_codec_pa_mute),
 
+	SND_SOC_DAPM_INPUT("Mic1"),
+
 	SND_SOC_DAPM_OUTPUT("HP Right"),
 	SND_SOC_DAPM_OUTPUT("HP Left"),
 };
 
-static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = {
-	/* Left DAC Routes */
+static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = {
+	/* Left ADC / DAC Routes */
+	{ "Left ADC", NULL, "ADC" },
 	{ "Left DAC", NULL, "DAC" },
 
-	/* Right DAC Routes */
+	/* Right ADC / DAC Routes */
+	{ "Right ADC", NULL, "ADC" },
 	{ "Right DAC", NULL, "DAC" },
 
 	/* Right Mixer Routes */
@@ -491,15 +619,21 @@
 	{ "Power Amplifier Mute", "Switch", "Power Amplifier" },
 	{ "HP Right", NULL, "Power Amplifier Mute" },
 	{ "HP Left", NULL, "Power Amplifier Mute" },
+
+	/* Mic1 Routes */
+	{ "Left ADC", NULL, "MIC1 Pre-Amplifier" },
+	{ "Right ADC", NULL, "MIC1 Pre-Amplifier" },
+	{ "MIC1 Pre-Amplifier", NULL, "Mic1"},
+	{ "Mic1", NULL, "VMIC" },
 };
 
 static struct snd_soc_codec_driver sun4i_codec_codec = {
 	.controls		= sun4i_codec_widgets,
 	.num_controls		= ARRAY_SIZE(sun4i_codec_widgets),
-	.dapm_widgets		= sun4i_codec_dapm_widgets,
-	.num_dapm_widgets	= ARRAY_SIZE(sun4i_codec_dapm_widgets),
-	.dapm_routes		= sun4i_codec_dapm_routes,
-	.num_dapm_routes	= ARRAY_SIZE(sun4i_codec_dapm_routes),
+	.dapm_widgets		= sun4i_codec_codec_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
+	.dapm_routes		= sun4i_codec_codec_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
 };
 
 static const struct snd_soc_component_driver sun4i_codec_component = {
@@ -516,7 +650,7 @@
 	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
 
 	snd_soc_dai_init_dma_data(dai, &scodec->playback_dma_data,
-				  NULL);
+				  &scodec->capture_dma_data);
 
 	return 0;
 }
@@ -532,6 +666,14 @@
 		.formats	= SUN4I_CODEC_FORMATS,
 		.sig_bits	= 24,
 	},
+	.capture = {
+		.stream_name	= "Capture",
+		.channels_min	= 1,
+		.channels_max	= 2,
+		.rates 		= SUN4I_CODEC_RATES,
+		.formats 	= SUN4I_CODEC_FORMATS,
+		.sig_bits	= 24,
+	 },
 };
 
 static const struct regmap_config sun4i_codec_regmap_config = {
@@ -569,6 +711,27 @@
 	return link;
 };
 
+static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w,
+				 struct snd_kcontrol *k, int event)
+{
+	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(w->dapm->card);
+
+	if (scodec->gpio_pa)
+		gpiod_set_value_cansleep(scodec->gpio_pa,
+					 !!SND_SOC_DAPM_EVENT_ON(event));
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget sun4i_codec_card_dapm_widgets[] = {
+	SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
+};
+
+static const struct snd_soc_dapm_route sun4i_codec_card_dapm_routes[] = {
+	{ "Speaker", NULL, "HP Right" },
+	{ "Speaker", NULL, "HP Left" },
+};
+
 static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
 {
 	struct snd_soc_card *card;
@@ -583,6 +746,10 @@
 
 	card->dev		= dev;
 	card->name		= "sun4i-codec";
+	card->dapm_widgets	= sun4i_codec_card_dapm_widgets;
+	card->num_dapm_widgets	= ARRAY_SIZE(sun4i_codec_card_dapm_widgets);
+	card->dapm_routes	= sun4i_codec_card_dapm_routes;
+	card->num_dapm_routes	= ARRAY_SIZE(sun4i_codec_card_dapm_routes);
 
 	return card;
 };
@@ -634,11 +801,25 @@
 		return -EINVAL;
 	}
 
+	scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
+						  GPIOD_OUT_LOW);
+	if (IS_ERR(scodec->gpio_pa)) {
+		ret = PTR_ERR(scodec->gpio_pa);
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Failed to get pa gpio: %d\n", ret);
+		return ret;
+	}
+
 	/* DMA configuration for TX FIFO */
 	scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA;
 	scodec->playback_dma_data.maxburst = 4;
 	scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 
+	/* DMA configuration for RX FIFO */
+	scodec->capture_dma_data.addr = res->start + SUN4I_CODEC_ADC_RXDATA;
+	scodec->capture_dma_data.maxburst = 4;
+	scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
 	ret = snd_soc_register_codec(&pdev->dev, &sun4i_codec_codec,
 				     &sun4i_codec_dai, 1);
 	if (ret) {
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
index ba272e2..deb597f 100644
--- a/sound/soc/tegra/tegra_alc5632.c
+++ b/sound/soc/tegra/tegra_alc5632.c
@@ -101,12 +101,16 @@
 
 static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
 {
+	int ret;
 	struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(rtd->card);
 
-	snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET,
-			      &tegra_alc5632_hs_jack,
-			      tegra_alc5632_hs_jack_pins,
-			      ARRAY_SIZE(tegra_alc5632_hs_jack_pins));
+	ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+				    SND_JACK_HEADSET,
+				    &tegra_alc5632_hs_jack,
+				    tegra_alc5632_hs_jack_pins,
+				    ARRAY_SIZE(tegra_alc5632_hs_jack_pins));
+	if (ret)
+		return ret;
 
 	if (gpio_is_valid(machine->gpio_hp_det)) {
 		tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det;
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 2160400..e485278 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -199,7 +199,8 @@
 
 static int tegra_wm8903_remove(struct snd_soc_card *card)
 {
-	struct snd_soc_pcm_runtime *rtd = &(card->rtd[0]);
+	struct snd_soc_pcm_runtime *rtd =
+		snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct snd_soc_codec *codec = codec_dai->codec;
 	struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
diff --git a/sound/synth/emux/emux_nrpn.c b/sound/synth/emux/emux_nrpn.c
index 00fc005..9729a15 100644
--- a/sound/synth/emux/emux_nrpn.c
+++ b/sound/synth/emux/emux_nrpn.c
@@ -48,7 +48,8 @@
  * convert NRPN/control values
  */
 
-static int send_converted_effect(struct nrpn_conv_table *table, int num_tables,
+static int send_converted_effect(const struct nrpn_conv_table *table,
+				 int num_tables,
 				 struct snd_emux_port *port,
 				 struct snd_midi_channel *chan,
 				 int type, int val, int mode)
@@ -179,7 +180,7 @@
 }
 
 
-static struct nrpn_conv_table awe_effects[] =
+static const struct nrpn_conv_table awe_effects[] =
 {
 	{ 0, EMUX_FX_LFO1_DELAY,	fx_lfo1_delay},
 	{ 1, EMUX_FX_LFO1_FREQ,	fx_lfo1_freq},
@@ -266,7 +267,7 @@
 	return -(val - 64) * gs_sense[FX_VIBDELAY] / 50;
 }
 
-static struct nrpn_conv_table gs_effects[] =
+static const struct nrpn_conv_table gs_effects[] =
 {
 	{32, EMUX_FX_CUTOFF,	gs_cutoff},
 	{33, EMUX_FX_FILTERQ,	gs_filterQ},
@@ -350,7 +351,7 @@
 	return -(val - 64) * xg_sense[FX_RELEASE] / 64;
 }
 
-static struct nrpn_conv_table xg_effects[] =
+static const struct nrpn_conv_table xg_effects[] =
 {
 	{71, EMUX_FX_CUTOFF,	xg_cutoff},
 	{74, EMUX_FX_FILTERQ,	xg_filterQ},
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 18f5664..1f09d95 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -675,6 +675,8 @@
 
 void snd_usb_autosuspend(struct snd_usb_audio *chip)
 {
+	if (atomic_read(&chip->shutdown))
+		return;
 	if (atomic_dec_and_test(&chip->active))
 		usb_autopm_put_interface(chip->pm_intf);
 }
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 5b4c58c..cc39f63 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -112,7 +112,7 @@
 	struct usb_interface *iface;
 	const struct snd_usb_audio_quirk *quirk;
 	struct snd_rawmidi *rmidi;
-	struct usb_protocol_ops *usb_protocol_ops;
+	const struct usb_protocol_ops *usb_protocol_ops;
 	struct list_head list;
 	struct timer_list error_timer;
 	spinlock_t disc_lock;
@@ -671,31 +671,32 @@
 	}
 }
 
-static struct usb_protocol_ops snd_usbmidi_standard_ops = {
+static const struct usb_protocol_ops snd_usbmidi_standard_ops = {
 	.input = snd_usbmidi_standard_input,
 	.output = snd_usbmidi_standard_output,
 	.output_packet = snd_usbmidi_output_standard_packet,
 };
 
-static struct usb_protocol_ops snd_usbmidi_midiman_ops = {
+static const struct usb_protocol_ops snd_usbmidi_midiman_ops = {
 	.input = snd_usbmidi_midiman_input,
 	.output = snd_usbmidi_standard_output,
 	.output_packet = snd_usbmidi_output_midiman_packet,
 };
 
-static struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = {
+static const
+struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = {
 	.input = snd_usbmidi_maudio_broken_running_status_input,
 	.output = snd_usbmidi_standard_output,
 	.output_packet = snd_usbmidi_output_standard_packet,
 };
 
-static struct usb_protocol_ops snd_usbmidi_cme_ops = {
+static const struct usb_protocol_ops snd_usbmidi_cme_ops = {
 	.input = snd_usbmidi_cme_input,
 	.output = snd_usbmidi_standard_output,
 	.output_packet = snd_usbmidi_output_standard_packet,
 };
 
-static struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops = {
+static const struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops = {
 	.input = ch345_broken_sysex_input,
 	.output = snd_usbmidi_standard_output,
 	.output_packet = snd_usbmidi_output_standard_packet,
@@ -795,7 +796,7 @@
 	}
 }
 
-static struct usb_protocol_ops snd_usbmidi_akai_ops = {
+static const struct usb_protocol_ops snd_usbmidi_akai_ops = {
 	.input = snd_usbmidi_akai_input,
 	.output = snd_usbmidi_akai_output,
 };
@@ -835,7 +836,7 @@
 	urb->transfer_buffer_length = 2 + count;
 }
 
-static struct usb_protocol_ops snd_usbmidi_novation_ops = {
+static const struct usb_protocol_ops snd_usbmidi_novation_ops = {
 	.input = snd_usbmidi_novation_input,
 	.output = snd_usbmidi_novation_output,
 };
@@ -867,7 +868,7 @@
 	urb->transfer_buffer_length = count;
 }
 
-static struct usb_protocol_ops snd_usbmidi_raw_ops = {
+static const struct usb_protocol_ops snd_usbmidi_raw_ops = {
 	.input = snd_usbmidi_raw_input,
 	.output = snd_usbmidi_raw_output,
 };
@@ -883,7 +884,7 @@
 		snd_usbmidi_input_data(ep, 0, buffer + 2, buffer_length - 2);
 }
 
-static struct usb_protocol_ops snd_usbmidi_ftdi_ops = {
+static const struct usb_protocol_ops snd_usbmidi_ftdi_ops = {
 	.input = snd_usbmidi_ftdi_input,
 	.output = snd_usbmidi_raw_output,
 };
@@ -927,7 +928,7 @@
 	urb->transfer_buffer_length = ep->max_transfer;
 }
 
-static struct usb_protocol_ops snd_usbmidi_122l_ops = {
+static const struct usb_protocol_ops snd_usbmidi_122l_ops = {
 	.input = snd_usbmidi_us122l_input,
 	.output = snd_usbmidi_us122l_output,
 };
@@ -1060,7 +1061,7 @@
 	urb->transfer_buffer_length = ep->max_transfer - buf_free;
 }
 
-static struct usb_protocol_ops snd_usbmidi_emagic_ops = {
+static const struct usb_protocol_ops snd_usbmidi_emagic_ops = {
 	.input = snd_usbmidi_emagic_input,
 	.output = snd_usbmidi_emagic_output,
 	.init_out_endpoint = snd_usbmidi_emagic_init_out,
@@ -2206,7 +2207,7 @@
 	return 0;
 }
 
-static struct snd_rawmidi_global_ops snd_usbmidi_ops = {
+static const struct snd_rawmidi_global_ops snd_usbmidi_ops = {
 	.get_port_info = snd_usbmidi_get_port_info,
 };
 
diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
index 9581089..c19a5dd 100644
--- a/sound/usb/misc/ua101.c
+++ b/sound/usb/misc/ua101.c
@@ -1037,7 +1037,7 @@
 		return -ENXIO;
 	}
 	ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, usb_endpoint_num(epd));
-	ua->capture.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize);
+	ua->capture.max_packet_bytes = usb_endpoint_maxp(epd);
 
 	epd = &ua->intf[INTF_PLAYBACK]->altsetting[1].endpoint[0].desc;
 	if (!usb_endpoint_is_isoc_out(epd)) {
@@ -1045,7 +1045,7 @@
 		return -ENXIO;
 	}
 	ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, usb_endpoint_num(epd));
-	ua->playback.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize);
+	ua->playback.max_packet_bytes = usb_endpoint_maxp(epd);
 	return 0;
 }
 
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 0ce888d..2790256 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -793,7 +793,7 @@
 		return 0;
 
 	kcontrol->private_value &= ~(0xff << 24);
-	kcontrol->private_value |= newval;
+	kcontrol->private_value |= (unsigned int)newval << 24;
 	err = snd_ni_update_cur_val(list);
 	return err < 0 ? err : 1;
 }
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index b6c0c8e..23ea6d8 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1269,6 +1269,7 @@
 	case USB_ID(0x20b1, 0x3008): /* iFi Audio micro/nano iDSD */
 	case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */
 	case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */
+	case USB_ID(0x22d8, 0x0416): /* OPPO HA-1*/
 		if (fp->altsetting == 2)
 			return SNDRV_PCM_FMTBIT_DSD_U32_BE;
 		break;
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 8ee14f2..c4dc577 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -125,11 +125,9 @@
 static bool have_dup_chmap(struct snd_usb_substream *subs,
 			   struct audioformat *fp)
 {
-	struct list_head *p;
+	struct audioformat *prev = fp;
 
-	for (p = fp->list.prev; p != &subs->fmt_list; p = p->prev) {
-		struct audioformat *prev;
-		prev = list_entry(p, struct audioformat, list);
+	list_for_each_entry_continue_reverse(prev, &subs->fmt_list, list) {
 		if (prev->chmap &&
 		    !memcmp(prev->chmap, fp->chmap, sizeof(*fp->chmap)))
 			return true;
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index 61d5dc2..dd40ca9 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -166,7 +166,7 @@
 			/* set the buffer pointer */
 			urb->transfer_buffer = runtime->dma_area + subs->hwptr * usX2Y->stride;
 			if ((subs->hwptr += count) >= runtime->buffer_size)
-			subs->hwptr -= runtime->buffer_size;			
+				subs->hwptr -= runtime->buffer_size;
 		}
 	else
 		urb->transfer_buffer = subs->tmpbuf;